Adds browser (WASM) support#34
Conversation
Ideally they shouldn't, but you need to emit Although it depends on the bundler and whether they support Either way, if possible, I'd really recommend to avoid |
|
This is great to know @RReverser - I'll look into updating this. |
|
This has now been updated as an ES Module via |
|
@RReverser by chance, have you ever gotten Emscripten outputs to work seamlessly with Next.js? So far it has been a bit challenging:
As of now my best solution for Next.js is the one above requiring developers to install |
|
Hm no I didn't do anything Next.js-specific, I'm afraid you'll need to play with it yourself.
If it's about the file extension, you can just change it to I forgot to mention one other thing, but it might help here too - instead of custom Makefile, you can integrate Wasm building into binding.gyp. See here how I did that in Sharp / feel free to borrow the common.gypi until we find a way to upstream it to emnapi (the blocker was that it won't work on Windows yet): https://github.com/lovell/sharp/pull/3522/files#diff-61fe5790e62b9d1af82b5332536fb4bdc899528b095c22f43f9f10068e91eeb7 |
|
@gregnr I saw that How much more work is needed on this PR? (and approximately how hard is each thing?) We at @upleveled would love to test SafeQL by @Newbie012 with our next cohort of bootcamp students (some of whom use Windows) in mid-February 2024, and I think that this PR would offer us a chance to do so! If there's an early version that @Eprince-hub or other people on our team can try out, we'd love to give it a shot, even before this PR is merged :) |
|
Elsewhere in the ecosystem, another WebAssembly implementation of |
|
@pyramation @karlhorky We've been using the WASM library at Supabase in a forked package for a while and would like to merge this PR. Are there any outstanding issues (beside the merge conflicts) that needs to be resolved? |
|
@karlhorky This PR is good to go now. The challenges above with Next.js are solvable using I've updated the base branch to I couldn't find any build/deploy CI automation in this repo so didn't set anything up there on the WASM side (manual wasm build + NPM deploy for now). Let me know if there's a better way to do this. |
|
Thank you for this amazing work :) oops, I deleted |
|
OK, I've published an rc version Once we verify on a few machines this is good, sounds like we can merge the wasm-feature branch into 15-latest and publish 15.0.4 or later |
|
I tried to install this on a Windows machine today using |
|
With the npm latest version |
|
The package is not published onto Supabase S3 bucket for some reason. You need to run |
|
ok, so sounds like this works for linux, but not windows yet, and we need to get the binary publish |
Adds WASM support using the incredible emnapi project that implements Node's N-API for Emscripten. This means no new bindings needed to be built - we can reuse the existing Node-API bindings and simply target WASM.
Some implementation notes:
Build method
yarn build:wasmwhich uses aMakefileunder the hood.emnapiexperimentally supports node-gyp, but node-gyp doesn't yet support static library linking when cross-compiling. TheMakefilealso gives us a cleaner way to load and build thelibpg_querysource.yarn build:wasmruns via Docker to make the build process easier for devs who don't have emsdk installed.I needed to patch one line of code inThis is now merged.libpg_query'sMakefileto getlibpg_query.ato build properly for Emscripten, hence the reference to my fork at https://github.com/gregnr/libpg_query.git. Once that PR is merged I will link back to the original repo.Output format
I opted for Emscripten'sSINGLE_FILE=1flag for now which bundles the.wasmoutput into the accompanying.jsfile as base64. The.jsfile ends up just under 2MB, but this makes NPM distribution and bundling much simpler (otherwise devs will need to add special rules to their web bundler configs to import the.wasmfile properly). I tested serving the.jsfile over a web server that uses standard gzip compression, and the compressed file size went down to ~450Kb, which is more approachable.SINGLE_FILE=1, we now useEXPORT_ES6=1which outputs the.jsand.wasmseparately, where the.jsfile is built as an ES Module that includes aimport.meta.urlreference to the WASM file, as noted below by @RReverser. Bundlers like webpack have first class support forimport.meta.url, meaning no extra configuration is required to load the.wasmfile.Async only + single threaded for now
init()command before they can use them.pthreadand usesemnapi'semnapi-basiclib. This means that asynchronous logic (ie.AsyncWorker, etc) isn't truly multithreaded - it's just mocked in the main thread. It is possible to enablepthreadwhich is implemented as WebWorkers under the hood, but this method requiresSharedArrayBufferwhich has much stricter security requirements and makes deploying much more difficult/nuanced. If we are still interested in executing WASM in a different thread, I suggest we manually wrap the current output in WebWorkers and manage the back-and-forth communication ourselves without usingSharedArrayBuffer.Consumption
exportstopackage.jsonwhich should tell each runtime/bundler which entry point to use - meaning Node.js will continue to use the native NAPI bindings and web bundlers will use the WASM build.I haven't yet tested publishing this to NPM and using it, but plan to shortly.This has now been tested when imported as a published NPM module:@gregnr/libpg-query@13.4.0-dev.10. Works in both Node (uses native NAPI) and browser (uses WASM).Webpack POC
./testas a means to test the lib in the browser.