My goal is to be able to publish a Web Worker NPM package which can be imported normally (import MyPkg from 'my-pkg'
) without requiring the user to import it with worker-loader
(inline or otherwise)
To accomplish this, I've tried using a Babel build script as well as Webpack with worker-loader
.
In the following examples there are two projects: the Web Worker package ("Package") which is npm link
ed to a test application ("App").
The Package is split into two files: entry.webpack.js
and index.worker.js
. The entry, when built and moved to /dist
is designated as the main
file in the package.json, and it currently looks like this:
entry.webpack.js
var MyPkg = require('worker-loader!./index.worker.js')
module.exports = MyPkg
index.worker.js
// This is just example code. It doesn't really matter
// what this code does so long as it ends up being run
// as a Web Worker.
var selfRef = self;
function ExampleWorker () {
console.log('Running Worker...');
setTimeout(function () {
// wait 10 seconds then post a message
selfRef.postMessage({foo: "bar"});
}, 10000)
}
module.exports = ExampleWorker
I then bundle the Package with Webpack:
package.json
"build": "rm -rf dist/*.* && webpack --progress"
webpack.config.js
module.exports = {
mode: 'production',
devtool: 'source-map',
entry: __dirname + '/src/entry.webpack.js',
output: {
filename: 'bundle.js',
path: __dirname + '/dist'
},
optimization: {
minimize: false
}
}
This generates two files: bundle.js
and a Web Worker file as a hash: [hash].worker.js
with the code we want evaluated in it. They key part in this, though, is that because we used worker-loader
inline to import, the webpack compiled output looks something like:
module.exports = function() {
return new Worker(__webpack_require__.p + "53dc9610ebc22e0dddef.worker.js");
};
Finally, the App should be able to import it and use it like this:
App.js
import MyPkg from 'my-pkg'
// logging MyPkg here produces `{}`
const worker = new MyPkg()
// That throws an Error:
// Uncaught TypeError: _my_pkg__WEBPACK_IMPORTED_MODULE_4___default.a is not a constructor
worker.onmessage = event => {
// this is where we'd receive our message from the web worker
}
However, you can get it to work if, in the App itself you import the worker build like this:
import MyPkg from 'my-pkg/dist/53dc9610ebc22e0dddef.worker.js'
But, it's a requirement of the package to:
A) NOT require applications using the package to have to explicitly install worker-loader
and
B) not have to reference the my-pkg/dist/[hash].worker.js
explicitly.
I've tried also designating the built [hash].worker.js' as the
main` in package.json but that doesn't work either.
Edit 1: I forgot to mention that I'm basing all of this off of how react-pdf
does it. If you take a look in /src/entry.webpack.js
and follow how it works throughout the package you'll see a few similarities.
you could try worker-loader with option:
{
test: /\.worker\.js$/,
use: {
loader: 'worker-loader',
options: {
name: '[name].[hash:8].js',
// notice here
inline: true,
fallback: false
}
}
},