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

POC: Using WebAssembly build of libsass #2220

Closed
wants to merge 5 commits into
base: master
from

Conversation

Projects
None yet
4 participants
@kwonoj
Copy link

kwonoj commented Jan 19, 2018

Not to be merged. More of proof of concept to illustrate high-level codeflows with pros & cons, and roadmaps to make it happen. This PR aims to provide proof-of-concept implementation of #2011, replaces current native libsass module into WebAssembly based binary.

How to run demo

npm install && node ./lib/loadModule.js. I haven't spend time to node.js version compatibility for bootstrap.ts, so ensure it doesn't emit error (and wget is available on shell too).

you can see version information, and simplest sass compilation result.

image

Code structure

Building libsass requires several native dependency & emsdk setup, but only necessary when need to bump up libsass itself. Instead of managing native build in single repo, this PR uses prebuilt binary via docker-libsass-wasm, preconfigured docker image generates specified libsass version of binary. In this PR, it builds latest beta 3.5.0.beta.3. node-sass uses tagged release from repo via bootstrap script, nothing more than just download binaries and put under correct location.

Prebuilt binary exposes C interface of libsass - in loadModule.js, node-sass creates corresponding bindings to C functions, wraps C interface to javascript functions with proper pointer interop, and finally exposes loadSass interface to compile wasm binary and build wrapped binding into sass module. In this PR, it exposes sass.info and naïve version of renderSync which only accepts data string.

Pros & cons

Pros

  • does not need native module anymore
  • supports asm.js as fallback for node.js doesn't support native wasm

Cons

  • Wasm compliation happens asynchronously, introduces breaking change interface loadSass(): Promise<sass> to prepare sass module correctly
  • Basically this is rewriting of node-sass, dropping existing native bindings
  • cabllback based async bindings (i.e render) is now won't be well supported, as it's basically not supported to create async fn via libuv queue. To provide interface level compatibility could trap out sync version into nexttick, but not ideal. (there are some experimental approach like Emterpreter but it is unsure it'll even work with libsass)

Roadmap (if this is a thing to go)

  • create wrapped interfaces / pointer interop for all necessary libsass interface
  • migrate existing synchronous sass interface (renderSync, ...)
  • simple nexttick trapping for async interface (render, ...)
  • evaluate empreter to replace ☝️
  • migrate test cases to verify sanity
  • explore possibility of creating correct async interface instead of trapping
  • (good to have) run libsass test cases to wasm binary, to verify sanity of wasm binary itself

kwonoj added some commits Jan 19, 2018

@kwonoj kwonoj referenced this pull request Jan 19, 2018

Open

Compile to WebAssembly #2011

@kwonoj

This comment has been minimized.

Copy link

kwonoj commented Jan 19, 2018

Feel freely close PR if this isn't way to go.

@xzyfer

This comment has been minimized.

Copy link
Contributor

xzyfer commented Jan 19, 2018

Thanks for this POC @kwonoj. To clarify, if we adopt WASM we cannot support async execution i.e. render, custom functions and custom importers?

@kwonoj

This comment has been minimized.

Copy link

kwonoj commented Jan 19, 2018

few things need to be evaluated. current wasm design so far at least doesn't have way to queue sync functions and control stack execution in async flow.

for emscripten side there's empreter which looks interesting, but that's something I haven't tried in this poc. I wouldn't say it's impossible forever, but safe to assume it'll be tricky.

@kwonoj

This comment has been minimized.

@xzyfer

This comment has been minimized.

Copy link
Contributor

xzyfer commented Jan 20, 2018

I've reached out to the N-API to get some clarification whether the N-APIs place nicer with WASM

@kwonoj

This comment has been minimized.

Copy link

kwonoj commented Jan 20, 2018

It'd be interesting if n-api have way to support it. If there isn't, I believe emterpreter is way for immediate direction to go with wasm.

@jayphelps

This comment has been minimized.

Copy link

jayphelps commented Jan 20, 2018

Wasm compliation happens asynchronously, introduces breaking change interface loadSass(): Promise to prepare sass module correctly

It shouldn't have to be, if that's not desired. 😄 Emscripten supports sync via new WebAssembly.Module(binary) BINARYEN_ASYNC_COMPILATION=0. As long as you don't need browser support, because browsers won't allow you to synchronously load binary data on the main thread via fetch() or XMLHttpRequest

@kwonoj

This comment has been minimized.

Copy link

kwonoj commented Jan 20, 2018

oh I had some issue when I tried on browsers, so it doesn't have any limitation to sync compile on nodejs? @jayphelps

@jayphelps

This comment has been minimized.

Copy link

jayphelps commented Jan 20, 2018

@kwonoj yep, works good in latest node. Dunno what the minimum version is off-hand though.

const module = new WebAssembly.Module(new Uint8Array([
  0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00
]));
@kwonoj

This comment has been minimized.

Copy link

kwonoj commented Jan 20, 2018

Oh good to know. I still prefer async compilation but at least we have option here.

@kwonoj

This comment has been minimized.

Copy link

kwonoj commented Jan 20, 2018

@jayphelps uh.. second thought: sync loading works with asm.js build as well? (guess so?) 😅 if it's not., I don't think node-sass can aim native wasm supported node.js version only.

@jayphelps

This comment has been minimized.

Copy link

jayphelps commented Jan 20, 2018

👍 asm.js compiles the same as JS, so to do it’s normaly sync but can be async with <script async> or in node with the vm module stuff.

@xzyfer

This comment has been minimized.

Copy link
Contributor

xzyfer commented Jan 20, 2018

FWIW we have no intention to have browsers compatibility. There's already https://github.com/medialize/sass.js/ for that use case.

@kwonoj

This comment has been minimized.

Copy link

kwonoj commented Jan 20, 2018

I don't expect browser compat too. mostly aims recent version of node, including non-native wasm versions as well via asm.js.

@mgreter mgreter referenced this pull request Feb 6, 2018

Open

Web Assembly #74

@kwonoj

This comment has been minimized.

Copy link

kwonoj commented Mar 7, 2018

Closing as inactive. I believe PR itself has served sufficiently for proof verification for the possible road.

@kwonoj kwonoj closed this Mar 7, 2018

@kwonoj kwonoj deleted the kwonoj:feat-wasm branch Mar 7, 2018

@nschonni

This comment has been minimized.

Copy link
Contributor

nschonni commented Mar 8, 2018

@kwonoj thanks for working through this ❤️

@xzyfer

This comment has been minimized.

Copy link
Contributor

xzyfer commented Mar 14, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment