Skip to content

Commit

Permalink
Instantiate wasm synchronously
Browse files Browse the repository at this point in the history
  • Loading branch information
devongovett committed Aug 19, 2023
1 parent 7209ff3 commit ef114ec
Show file tree
Hide file tree
Showing 5 changed files with 13 additions and 62 deletions.
9 changes: 2 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,20 +112,15 @@ All of the APIs in `@parcel/watcher` support the following options, which are pa

The `@parcel/watcher-wasm` package can be used in place of `@parcel/watcher` on unsupported platforms. It relies on the Node `fs` module, so in non-Node environments such as browsers, an `fs` polyfill will be needed. The `@parcel/watcher-wasm` package is published as an ESM-only module.

The WASM API is identical, except you must initialize it first.
**Note**: the WASM implementation is significantly less efficient than the native implementations because it must crawl the file system to watch each directory individually. Use the native `@parcel/watcher` package wherever possible.

```js
import init, {subscribe} from '@parcel/watcher-wasm';

// Load and initialize the WASM module.
await init();
import {subscribe} from '@parcel/watcher-wasm';

// Use the module as documented above.
subscribe(/* ... */);
```

By default, `init` loads the WASM file relative to its JavaScript, but you can pass a URL to the `watcher.wasm` file if you are hosting it elsewhere.

## Who is using this?

- [Parcel 2](https://parceljs.org/)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@parcel/watcher",
"version": "2.3.0-alpha.1",
"version": "2.3.0-alpha.2",
"main": "index.js",
"types": "index.d.ts",
"repository": {
Expand Down
1 change: 0 additions & 1 deletion test/since.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ describe('since', () => {
if (backend === 'wasm') {
if (!watcherWasm) {
watcherWasm = await import('../wasm/index.mjs');
await watcherWasm.default();
}
watcher = watcherWasm;
} else {
Expand Down
1 change: 0 additions & 1 deletion test/watcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ describe('watcher', () => {
before(async () => {
if (backend === 'wasm') {
watcher = await import('../wasm/index.mjs');
await watcher.default();
} else {
watcher = watcherNative;
}
Expand Down
62 changes: 10 additions & 52 deletions wasm/index.mjs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { Environment, napi } from 'napi-wasm';
import fs from 'fs';
import Path from 'path';
import micromatch from 'micromatch';
import isGlob from 'is-glob';
import { createWrapper } from '../wrapper.js';

let wrapper, env;
let env;
let encoder = new TextEncoder;

let constants = {
Expand Down Expand Up @@ -300,56 +298,16 @@ function align(len, p) {
return Math.ceil(len / p) * p;
}

export default async function init(input) {
input = input ?? new URL('../build/Debug/watcher.wasm', import.meta.url);
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
input = fetchOrReadFromFs(input);
}

const { instance } = await load(await input, {
napi,
env: wasm_env,
wasi_snapshot_preview1: wasi
});

env = new Environment(instance);
wrapper = createWrapper(env.exports);
}

async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
} catch (e) {
if (module.headers.get('Content-Type') != 'application/wasm') {
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
} else {
throw e;
}
}
}
let wasmBytes = fs.readFileSync(new URL('../build/Debug/watcher.wasm', import.meta.url));
let wasmModule = new WebAssembly.Module(wasmBytes);
let instance = new WebAssembly.Instance(wasmModule, {
napi,
env: wasm_env,
wasi_snapshot_preview1: wasi
});

const bytes = await module.arrayBuffer();
return await WebAssembly.instantiate(bytes, imports);
} else {
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
return { instance, module };
} else {
return instance;
}
}
}

async function fetchOrReadFromFs(inputPath) {
try {
const fs = await import('fs');
return fs.readFileSync(inputPath);
} catch {
return fetch(inputPath);
}
}
env = new Environment(instance);
let wrapper = createWrapper(env.exports);

export function writeSnapshot(dir, snapshot, opts) {
return wrapper.writeSnapshot(dir, snapshot, opts);
Expand Down

0 comments on commit ef114ec

Please sign in to comment.