A webpack loader that moves a module and its dependencies into a Web Worker, automatically reflecting exported functions as asynchronous proxies.
- Bundles a tiny, purpose-built RPC implementation into your app
- If exported module methods are already async, signature is unchanged
- Supports synchronous and asynchronous worker functions
- Works beautifully with async/await
- Imported value is instantiable, just a decorated
Worker
npm install -D workerize-loader
worker.js:
// block for `time` ms, then return the number of loops we could run in that time:
export function expensive(time) {
let start = Date.now(),
count = 0
while (Date.now() - start < time) count++
return count
}
index.js: (our demo)
import worker from 'workerize-loader!./worker'
let instance = worker() // `new` is optional
instance.expensive(1000).then( count => {
console.log(`Ran ${count} loops`)
})
Type: Boolean
Default: false
You can also inline the worker as a BLOB with the inline
parameter
// webpack.config.js
{
loader: 'workerize-loader',
options: { inline: true }
}
or
import worker from 'workerize-loader?inline!./worker'
About Babel
If you're using Babel in your build, make sure you disabled commonJS transform. Otherwize, workerize-loader won't be able to retrieve the list of exported function from your worker script :
{
test: /\.js$/,
loader: "babel-loader",
options: {
presets: [
[
"env",
{
modules: false,
},
],
]
}
}
Workerize-loader supports browsers that support Web Workers - that's IE10+. However, these browsers require a polyfill in order to use Promises, which Workerize-loader relies on. It is recommended that the polyfill be installed globally, since Webpack itself also needs Promises to load bundles.
The smallest implementation is the one we recommend installing:
npm i promise-polyfill
Then, in the module you are "workerizing", just add it as your first import:
import 'promise-polyfill/src/polyfill';
All worker code can now use Promises.
To test a module that is normally imported via workerize-loader
when not using Webpack, import the module directly in your test:
-const worker = require('workerize-loader!./worker.js');
+const worker = () => require('./worker.js');
const instance = worker();
To test modules that rely on workerized imports when not using Webpack, you'll need to dig into your test runner a bit. For Jest, it's possible to define a custom transform
that emulates workerize-loader on the main thread:
// in your Jest configuration
{
"transform": {
"workerize-loader(\\?.*)?!(.*)": "<rootDir>/workerize-jest.js"
}
}
... then add the workerize-jest.js
shim to your project:
module.exports = {
process(src, filename, config, options) {
return 'module.exports = () => require(' + JSON.stringify(filename.replace(/.+!/,'')) + ')';
},
};
Now your tests and any modules they import can use workerize-loader!
prefixes.
The inner workings here are heavily inspired by worker-loader. It's worth a read!