Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: minimal swipl-web #4

Open
jeswr opened this issue Sep 6, 2022 · 5 comments
Open

feat: minimal swipl-web #4

jeswr opened this issue Sep 6, 2022 · 5 comments

Comments

@jeswr
Copy link
Collaborator

jeswr commented Sep 6, 2022

This might be a more appropriate issue to open in https://github.com/SWI-Prolog/swipl-devel/ down the line; but I think it is fine to keep it here for now as I don't expect this will be a priority for anyone anytime soon.

It would be nice to have a much smaller build of swipl-web that does not make use of the path, fs and crypto modules; and also does not do any fetch handling internally.

This means that use cases with apps that just want to run basic queries don't need to import unecessary code into their apps.

I'm analyse tree-shaking downstream can offer for this particular file; which could well make this a moot point to solve anyway.

@rla
Copy link
Collaborator

rla commented Sep 8, 2022

I believe this depends on emscripten-core/emscripten#5828. It would likely make cross-environment usage also easier. "Want emulated filesystem? Just import @something/emulated_filesystem and mount to the Module".

Regarding loadable code size, it's dominated by .wasm and .data (Prolog), so the gain might not be that good:

  • swipl-web.data 5.5 MiB
  • swipl-web.wasm 1.8MiB
  • swipl.js 174.4 KiB

There is also WASI-SDK which has own libc, uses similar compiler setup with clang as Emscripten but does not build any sort of JS at all. libc (also posix?) emulation is done inside wasm binary, not outside: https://github.com/WebAssembly/wasi-sdk. Might be worth to investigate.

@rla
Copy link
Collaborator

rla commented Sep 8, 2022

Code size regarding C/wasm is also discussed in https://swi-prolog.discourse.group/t/wiki-discussion-swi-prolog-in-the-browser-using-wasm/5651/109

We definitely want to distribute the full build with as much included as possible but also the/a minimal build? For the minimal build:

  • Include no packages?
  • Include no boot/library, is this useful for something?

The NPM package can contain things side-by-side in dist subdirectories. It would not be too difficult to make the Docker-based build produce binaries in different weight classes. Anyone needing something really minimal could always build their own too.

@rla
Copy link
Collaborator

rla commented Oct 6, 2022

I also noticed that swipl-web.js contains references to modules path, fs and crypto while creating the Webpack example. But all these were only used when the running environment is node. It is interesting that this is inside supposedly a browser code. Replacing these modules with empty ones bundle-time will work:

https://github.com/rla/npm-swipl-wasm/blob/1057c488e777989ee0b1c9dc34878c82da444e2e/examples/webpack/webpack.config.js#L12

@jeswr
Copy link
Collaborator Author

jeswr commented Jan 19, 2023

It might also be worthwhile investigating the use of the closure compiler to reduce the size of the emitted JS. I did quickly try it but it looks like some fixes are required on pre-js and post-js first.

FAILED: src/swipl-web.js 
: && /emsdk/upstream/emscripten/emcc -O3 -DNDEBUG -O3 -s WASM=1 -s MODULARIZE=1 -s EXPORT_NAME=SWIPL -s NO_EXIT_RUNTIME=0 -s WASM_BIGINT=1 -s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS=@/swipl-devel/src/wasm/exports.json -s EXPORTED_RUNTIME_METHODS=@/swipl-devel/src/wasm/runtime_exports.json -s SINGLE_FILE -s ELIMINATE_DUPLICATE_FUNCTIONS=1 --pre-js /swipl-devel/src/wasm/pre.js --post-js /swipl-devel/src/wasm/prolog.js --closure 1 src/CMakeFiles/swipl-web.dir/pl-main.c.o -o src/swipl-web.js  src/libswipl.a  /gmp/lib/libgmp.a  /zlib-1.2.12/libz.a  -lm  -lrt  /zlib-1.2.12/libz.a  -lm  -lrt  packages/clib/memfile.a  packages/clib/files.a  packages/clib/uri.a  packages/clib/readutil.a  packages/clib/prolog_stream.a  packages/clib/md54pl.a  packages/clib/crypt.a  packages/clib/hashstream.a  packages/clib/sha4pl.a  packages/http/json.a  packages/http/http_stream.a  packages/semweb/turtle.a  packages/semweb/ntriples.a  packages/sgml/sgml2pl.a  packages/nlp/double_metaphone.a  packages/nlp/porter_stem.a  packages/nlp/isub.a  packages/nlp/snowball.a  packages/nlp/libstemmer_c/liblibstemmer.a  packages/zlib/zlib4pl.a && :
building:ERROR: Closure compiler run failed:

building:ERROR: /tmp/emscripten_temp_aodu0gm6/swipl-web.js.pp.js.jso.js.jso.js.jso.js.jso.js:5605:4: WARNING - [JSC_MISPLACED_ANNOTATION] Misplaced function annotation. This JSDoc is not attached to a function node. Are you missing parentheses?
  5605|  */ class Prolog {
            ^^^^^^^^^^^^^^
  5606|  constructor(module, args) {
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
  6530|  }
        ^^
  6531| }
        ^

/tmp/emscripten_temp_aodu0gm6/swipl-web.js.pp.js.jso.js.jso.js.jso.js.jso.js:6071:20: WARNING - [JSC_TYPE_PARSE_ERROR] Bad type annotation. expected closing } See https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler for more information.
  6071|  * @return {IOSTREAM*} as a number (pointer)
                            ^

/tmp/emscripten_temp_aodu0gm6/swipl-web.js.pp.js.jso.js.jso.js.jso.js.jso.js:6548:4: WARNING - [JSC_MISPLACED_ANNOTATION] Misplaced function annotation. This JSDoc is not attached to a function node. Are you missing parentheses?
  6548|  */ class Query {
            ^^^^^^^^^^^^^
  6549|  constructor(prolog, module, flags, pred, argv, map, fid) {
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
  6716|  }
        ^^
  6717| }
        ^

/tmp/emscripten_temp_aodu0gm6/swipl-web.js.pp.js.jso.js.jso.js.jso.js.jso.js:5919:33: ERROR - [JSC_REASSIGNED_CONSTANT] Constant reassigned: size
  5919|     if (!size instanceof Number) size = -1;
                                         ^^^^

/tmp/emscripten_temp_aodu0gm6/swipl-web.js.pp.js.jso.js.jso.js.jso.js.jso.js:6096:85: ERROR - [JSC_REFERENCE_BEFORE_DECLARE_ERROR] Illegal variable reference before declaration: flags
  6096|   const flags = opts.flags == undefined ? this.PL_WRT_QUOTED | this.PL_WRT_NEWLINE : flags;
                                                                                             ^^^^^

2 error(s), 3 warning(s)

emcc: error: closure compiler failed (rc: 2): /emsdk/node/14.18.2_64bit/bin/node --max_old_space_size=8192 /emsdk/upstream/emscripten/node_modules/.bin/google-closure-compiler --compilation_level ADVANCED_OPTIMIZATIONS --language_in ECMASCRIPT_2020 --language_out NO_TRANSPILE --emit_use_strict=false --externs /emsdk/upstream/emscripten/src/closure-externs/closure-externs.js --externs /emsdk/upstream/emscripten/src/closure-externs/node-externs.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/dgram.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/querystring.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/process.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/vm.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/child_process.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/tty.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/zlib.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/string_decoder.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/stream.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/repl.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/os.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/readline.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/buffer.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/tls.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/domain.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/util.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/https.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/dns.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/punycode.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/assert.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/net.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/cluster.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/events.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/http.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/path.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/fs.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/url.js --externs /emsdk/upstream/emscripten/third_party/closure-compiler/node-externs/core.js --js /tmp/emscripten_temp_aodu0gm6/swipl-web.js.pp.js.jso.js.jso.js.jso.js.jso.js --js_output_file tmpctaattkc.cc.js the error message may be clearer with -g1 and EMCC_DEBUG=2 set
ninja: build stopped: subcommand failed.
The command '/bin/sh -c /build-swipl.sh' returned a non-zero code: 1
ERROR: "build:wasm-docker:build" exited with 1.
ERROR: "build:wasm-docker" exited with 1.

@rla
Copy link
Collaborator

rla commented Jan 28, 2023

Seems like code is already minified. I'm not sure how much closure compiler could reduce it further.

It would still be nice to fix to errors. Seems like closure compiler wants to interpret jsdoc very strictly. Maybe the check can be turned off or those jsdoc nodes moved to constructors or otherwise fixed.

Error in if (!size instanceof Number) size = -1 seems to be fixed already.

Variable : flags in ternary-if should probably be opts.flags:

https://github.com/SWI-Prolog/swipl-devel/blob/d65e0686bc68da7525355c6b583e5784620258d0/src/wasm/prolog.js#L805

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants