From f5cb5564c559ece338b5c5fd3e199268b1b41dc3 Mon Sep 17 00:00:00 2001 From: Vedant Roy Date: Sun, 26 Apr 2020 19:14:14 -0400 Subject: [PATCH] fix(wasm): work with service workers (#334) BREAKING CHANGES: This change leverages `globalThis` and will fail in older environments where `globalThis` is not implemented. See https://caniuse.com/#search=WebAssembly and https://caniuse.com/#search=globalThis. If your environment doesn't support `globalThis`, please use an earlier version of this plugin. * Make wasm plugin work with service workers The code generated by @rollup/plugin-wasm breaks when executed in a service worker because window is undefined. * Add test for worker scenario and simplify the fix Instead of checking whether window is defined, we can just use globalThis. * Only run worker test if worker_threads supported --- packages/wasm/src/index.js | 2 +- packages/wasm/test/fixtures/worker.js | 11 +++++++++ packages/wasm/test/test.js | 34 +++++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 packages/wasm/test/fixtures/worker.js diff --git a/packages/wasm/src/index.js b/packages/wasm/src/index.js index 2332a68a8..b64485fba 100755 --- a/packages/wasm/src/index.js +++ b/packages/wasm/src/index.js @@ -30,7 +30,7 @@ export default function wasm(options = {}) { if (isNode) { buf = Buffer.from(src, 'base64') } else { - var raw = window.atob(src) + var raw = globalThis.atob(src) var rawLength = raw.length buf = new Uint8Array(new ArrayBuffer(rawLength)) for(var i = 0; i < rawLength; i++) { diff --git a/packages/wasm/test/fixtures/worker.js b/packages/wasm/test/fixtures/worker.js new file mode 100644 index 000000000..948d53a7c --- /dev/null +++ b/packages/wasm/test/fixtures/worker.js @@ -0,0 +1,11 @@ +import sample from './sample.wasm'; +// atob doesn't exist in node, so we fake it +// in the browser, globalThis.atob will exist +// eslint-disable-next-line no-undef +globalThis.atob = (str) => Buffer.from(str, 'base64').toString('binary'); +// trick the wasm loader into thinking we are in the browser +const realProcess = process; +// eslint-disable-next-line no-global-assign, no-undefined +process = undefined; +sample({}); +realProcess.exit(0); diff --git a/packages/wasm/test/test.js b/packages/wasm/test/test.js index 26487d800..a63e553ac 100755 --- a/packages/wasm/test/test.js +++ b/packages/wasm/test/test.js @@ -6,11 +6,15 @@ import wasm from '../dist/index'; const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor; -const testBundle = async (t, bundle) => { +const generateCode = async (bundle) => { const { output } = await bundle.generate({ format: 'cjs' }); const [{ code }] = output; - const func = new AsyncFunction('t', `let result;\n\n${code}\n\nreturn result;`); + return code; +}; +const testBundle = async (t, bundle) => { + const code = await generateCode(bundle); + const func = new AsyncFunction('t', `let result;\n\n${code}\n\nreturn result;`); return func(t); }; @@ -61,3 +65,29 @@ test('imports', async (t) => { }); await testBundle(t, bundle); }); + +try { + const { Worker } = require('worker_threads'); + test('worker', async (t) => { + t.plan(2); + + const bundle = await rollup({ + input: 'test/fixtures/worker.js', + plugins: [wasm()] + }); + const code = await generateCode(bundle); + const executeWorker = () => { + const worker = new Worker(code, { eval: true }); + return new Promise((resolve, reject) => { + worker.on('error', (err) => reject(err)); + worker.on('exit', (exitCode) => resolve(exitCode)); + }); + }; + await t.notThrowsAsync(async () => { + const result = await executeWorker(); + t.true(result === 0); + }); + }); +} catch (err) { + // worker threads aren't fully supported in Node versions before 11.7.0 +}