Skip to content

Commit

Permalink
Merge pull request #34 from FGasper/issue_33_modern_emscripten
Browse files Browse the repository at this point in the history
Update for current Emscripten and JQ.
  • Loading branch information
FGasper authored Oct 30, 2024
2 parents f821ca3 + dd67f2a commit 578c95c
Show file tree
Hide file tree
Showing 13 changed files with 3,721 additions and 253 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/all.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
on:
push:
branches:
- '*'
tags-ignore:
- '*'
pull_request:

jobs:
# As of this writing, Ubuntu’s emscripten doesn’t accommodate
# the Node.js bug described in
# https://github.com/emscripten-core/emscripten/issues/16913.
#
# So no Linux for now.
mac:
runs-on: macOS-latest
steps:
- run: node --version
- uses: actions/checkout@main
- run: brew install emscripten autoconf automake libtool
- run: make test
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "jq"]
path = jq
url = git@github.com:stedolan/jq.git
url = https://github.com/jqlang/jq
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ jq
node_modules
.*
Makefile
extern-post.js
post.js
pre.js
index.html
Expand Down
51 changes: 20 additions & 31 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,51 +9,40 @@
# ~/emsdk-portable/emsdk activate latest
# source ~/emsdk-portable/emsdk_env.sh

all: jq.asm.js jq.asm.min.js jq.wasm.js jq.wasm.min.js jq.wasm.wasm jq.asm.bundle.js jq.asm.bundle.min.js
all: jq.js jq.wasm

clean:
rm jq.*
rm -f jq jq.*

jq/configure: .gitmodules
jq/configure:
git submodule update --init
cd jq && \
git submodule update --init && \
patch -st src/main.c <../main.patch && \
autoreconf -fi

jq/jq.o: jq/configure
cd jq && \
emconfigure ./configure --disable-maintainer-mode --with-oniguruma=builtin && \
make clean && \
env CCFLAGS=-O2 emmake make LDFLAGS=-all-static CCFLAGS=-O2 -j4 && \
cp jq jq.o

jq.asm.js: jq/jq.o pre.js post.js
cd jq && \
emcc -O3 -s EXTRA_EXPORTED_RUNTIME_METHODS='["callMain"]' -s TOTAL_MEMORY=32MB -s MODULARIZE_INSTANCE=1 -s EXPORT_NAME="jq" -s WASM=0 --memory-init-file 1 --pre-js ../pre.js --post-js ../post.js jq.o -o ../jq.asm.js

jq.asm.min.js: node_modules/.bin/uglifyjs jq.asm.js
./node_modules/.bin/uglifyjs jq.asm.js -m -c -o jq.asm.min.js
jq/Makefile: jq/configure
cd jq && emconfigure ./configure --disable-maintainer-mode --disable-silent-rules --with-oniguruma=builtin

jq.asm.bundle.js: jq/jq.o pre.js post.js
cd jq && \
emcc -O3 -s EXTRA_EXPORTED_RUNTIME_METHODS='["callMain"]' -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE_INSTANCE=1 -s EXPORT_NAME="jq" -s WASM=0 --memory-init-file 0 --pre-js ../pre.js --post-js ../post.js jq.o -o ../jq.asm.bundle.js
jq/jq: jq/Makefile pre.js post.js extern-post.js
rm -f $@ # needed for emcc to replace existing file
cd jq && env CCFLAGS=-O2 emmake make V=1 VERBOSE=1 LDFLAGS="-all-static -s EXPORTED_RUNTIME_METHODS='[\"callMain\"]' -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE=1 -s EXPORT_NAME=jq -s WASM=1 --pre-js ../pre.js --post-js ../post.js --extern-post-js ../extern-post.js" CCFLAGS=-O2 -j4

jq.asm.bundle.min.js: node_modules/.bin/uglifyjs jq.asm.bundle.js
./node_modules/.bin/uglifyjs jq.asm.bundle.js -m -c -o jq.asm.bundle.min.js
jq.js: jq/jq jq.wasm
cp -f jq/jq ./jq.js

jq.wasm.js: jq/jq.o pre.js post.js
cd jq && \
emcc -O3 -s EXTRA_EXPORTED_RUNTIME_METHODS='["callMain"]' -s ALLOW_MEMORY_GROWTH=1 -s MODULARIZE_INSTANCE=1 -s EXPORT_NAME="jq" -s WASM=1 --pre-js ../pre.js --post-js ../post.js jq.o -o ../jq.wasm.js
jq/jq.wasm: jq/jq

jq.wasm.min.js: node_modules/.bin/uglifyjs jq.wasm.js
./node_modules/.bin/uglifyjs jq.wasm.js -m -c -o jq.wasm.min.js
jq.wasm: jq/jq jq/jq.wasm
cp -f jq/jq.wasm .

test: node_modules/.bin/tape
@PHONY:
test: jq.js node_modules/.bin/tape
node test.js

node_modules/.bin/tape:
npm install
node_modules/.bin/tape: node_modules

node_modules/.bin/uglifyjs: node_modules

node_modules/.bin/uglifyjs:
@PHONY:
node_modules:
npm install
54 changes: 17 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@

# jq-web

This is a build of [jq](https://github.com/stedolan/jq), the command-line JSON processor in Javascript using [Emscripten](http://kripken.github.io/emscripten-site/) along with a wrapper for making it usable as a library.
This is a WebAssembly build of [jq](https://github.com/jqlang/jq), the command-line JSON processor.

It runs in the browser.

### install and use
### Installation and use

```
npm install jq-web
```

```js
var jq = require('jq-web')
var jq = require('jq-web');

jq.json({
jq.then( jq => jq.json({
a: {
big: {
json: [
Expand All @@ -33,23 +33,6 @@ The code above returns the string `"empty of useless things"`.
You could do the same using the promised API with `jq.promised.json({...}).then(result => {})`. That is useful if you're loading a `.mem` or `.wasm` file, as the library won't return the correct results until these files are asynchronously fetched by the Emscripten runtime.
## What is each file

The [releases page](https://github.com/fiatjaf/jq-web/releases) has a bunch of different files you can download, here's what they all mean:

| file | description | pros | cons |
|----------------------|------------------------------------------------------------------------------|----------------------------------|----------------------------------------------------------------------------------------------------|
| jq.asm.js | [asm.js](http://asmjs.org/) version | runs in most places | requires loading jq.asm.js.mem |
| jq.asm.min.js | minified version of the above | idem | idem |
| jq.asm.js.mem | memory initialization file for asm.js, needed by jq.asm.js and jq.asm.min.js | | |
| jq.asm.bundle.js | asm.js version with memory initialization embedded | doesn't require loading anything | big and slow |
| jq.asm.bundle.min.js | minified version of the above | idem | the minification has no effect in the memory initialization stuff |
| jq.wasm.js | [WebAssembly](https://webassembly.org/) wrapper | smaller, much much faster | requires loading jq.wasm.wasm |
| jq.wasm.min.js | minified WebAssembly wrapper | | since this is just a wrapper around jq.wasm.wasm, the minification makes almost no difference here |
| jq.wasm.wasm | actual WebAssembly binary, loaded by jq.wasm.js and jq.wasm.min.js | | |

When in doubt, just use `jq.wasm.js`, it is the best!

### Webpack issues
#### `fs`
Expand All @@ -60,26 +43,23 @@ By default projects compiled with Emscripten look for `.wasm` files in the same
## Reference
`jq.json(<object>, <filter>) <object>` will take a Javascript object, or scalar, whatever, and dump it to JSON, then it will return whatever your filter outputs and try to convert that into a JS object. If you're loading `.mem` or `.wasm` files asynchronously this will return `{}` every time you call it until the loading is finished.
`jq-web` exports a promise that resolves to an object with `json` and `raw` methods.
`jq.raw(<json-string>, <filter>) <raw-output>` will take a string that will be passed as it is to jq (like if you were doing `echo '<json-string>' | jq <filter>` on the command line) then return a string with the raw STDOUT response. If you're loading `.mem` or `.wasm` files asynchronously this will return `'{}'` every time you call it until the loading is finished.
`jq.json(<object>, <filter>) <object>` will take a Javascript object, or scalar, whatever, and dump it to JSON, then it will return whatever your filter outputs and try to convert that into a JS object.
`jq.onInitialized.addListener(<function>)` registers a function to be called when `.mem` or `.wasm` files have finished loading and the library is ready to be used. You should register callbacks here to rerun your functions if you're using the sync API (above). If you're using the promised API (below) you don't ever need to look at this. Also, if you're using the sync API but just at a long time after the page is loaded and the user inputs something, for example, you may not need to use this at all.

`jq.promised.json(<object>, <filter>) Promise<object>` will do the same as `jq.json()` but returning a Promise to the result instead. This is safe to use anytime.

`jq.promised.raw(<json-string>, <filter>) Promise<raw-output>` will do the same as `jq.raw()` but returning a Promise to the result instead. This is safe to use anytime.
`jq.raw(<json-string>, <filter>, <flags>) <raw-output>` will take a string that will be passed as it is to jq (like if you were doing `echo '<json-string>' | jq <filter>` on the command line) then return a string with the raw STDOUT response.
## Build
1. [Install Emscripten from source](https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html#installation-instructions), we used `1.38.12`
2. Clone `jq-web` and `cd` into it
3. Look over the `Makefile` for more Emscripten instructions
4. `make`
* This may take a while the first time if you have never ran Emscripten before
1. Install Emscripten. There have been several API changes over time; version 3.1.31
is known to work.
2. Clone this repository, and `cd` into it.
3. `make`
* This may take a while if you have never run Emscripten before.
## Test
A handful of tests exist in `test.js` and are good place to start when verifying a build
1. `npm install` or `yarn`
2. `node test.js`
3. `./node_modules/live-server/live-server.js --open="index.html"`
A handful of tests exist in `test.js`. These are a good place to start when verifying a build.
To run them, do `make test`.
You can test browser functionality by running:
`./node_modules/live-server/live-server.js --open="index.html"`.
8 changes: 8 additions & 0 deletions extern-post.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
jq = jq().then( module => {
return { json: module.json, raw: module.raw };
} );

if (typeof exports === 'object' && typeof module === 'object')
module.exports = jq;
else if (typeof exports === 'object')
exports["jq"] = jq;
12 changes: 7 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ <h2>Check that <code>[5, "çá"]</code> is printed in the next line:</h2>
<pre><code id="result">

</code></pre>
<script src="jq.wasm.js"></script>
<script src="jq.js"></script>
<script>
// simple web test to ensure basic functionality, see test.js for a more complete test suite
jq.promised.json({foo: 5, un: 'à'}, '[.foo, "ç\\(.un)"]').then((res) => {
console.log(res)
window.result.innerHTML = JSON.stringify(res, null, 2)
})
jq
.then( jq => jq.json({foo: 5, un: 'à'}, '[.foo, "ç\\(.un)"]') )
.then((res) => {
console.log(res)
window.result.innerHTML = JSON.stringify(res, null, 2)
});
</script>
2 changes: 1 addition & 1 deletion jq
Submodule jq updated 257 files
12 changes: 0 additions & 12 deletions main.patch

This file was deleted.

Loading

0 comments on commit 578c95c

Please sign in to comment.