I have a web app that I compile with webpack. One of the modules that my code uses is named table.js
. Until recently, it's just been another module and has been compiled into my bundle.js
file with everything else.
Now I need to run table.js
in a Web Worker, so I need to pull it and its dependencies into a separate file that can be loaded both standalone and by my other modules.
At first I thought to include table.js
in my webpack.config.js
's entry
.
var config = {
...
entry: {
app: [ './src/main.js', './src/classes/table.js' ],
vendors: [],
},
...
}
That didn't work. Then I thought to separate it out like my vendors bundle.
var config = {
/* for vendors (and other modules) we have a CDN for */
addExternal: function (name, globalVar) {
this.externals[name] = globalVar;
this.entry.vendors.push(name);
},
/* for vendors we don't have a CDN for */
addVendor: function (name, path) {
this.resolve.alias[name] = path;
this.entry.vendors.push(name);
},
addPlugin: function (plugin) {
this.plugins.push(plugin);
},
entry: {
app: [ './src/main.js' ],
vendors: [],
table: [ __dirname + '/src/classes/table.js' ]
},
plugins: [],
externals: { },
output: {
path: __dirname + '/public/dist/',
filename: 'bundle.js',
publicPath: '/dist/',
sourceMapFile: '[file].map'
},
resolve: {
alias: { 'table': './src/classes/table.js' },
extensions: [ '', '.js', '.jsx' ]
},
...
}
/* add vendors and externals */
...
config.addPlugin(new CommonsChunkPlugin('vendors', 'vendors.js'));
config.addPlugin(new CommonsChunkPlugin('table', 'table.js'));
This seems to pull Table and its dependencies into a chunk of bundle.js
, 1.bundle.js
. Unfortunately, then calling import Table from 'table'
causes this error:
ERROR in CommonsChunkPlugin: While running in normal mode it's not allowed to use a non-entry chunk (table)
I also have a circular dependency between TableStore
and Table
. TableStore
needs to stay in bundle.js
because it shouldn't be loaded into the Web Worker. Previously, when I've needed to throw things into a separate chunk, I've done:
if (someThingNeedsRequiring) {
require.ensure([], () => {
require('something');
}
}
With the circular dependency, this doesn't seem to work.
/* table.js */
let _inWebWorker = self instanceof Window,
TableStore = null;
if (!_inWebWorker) {
require.ensure([], function() { TableStore = require('../stores/table-store'); } );
}
/* table-store.js */
import Table from 'table';
Could someone set me straight on the correct way to have my webpack.config.js
and how to use my import
s in my module files?
(It's been quite a while since I figured this out, and I haven't touched the project in nearly six months, so I may have missed some of the details. Comment if it's not working, and I'll try to figure out what I'm missing.)
webpack.config
It turns out there are two handy-dandy JavaScript packages for doing what I want:
worker-loader
andworkerjs
.I added this in my webpack.config.js:
require()
In order to specify that I want my class to be run in a WebWorker file, my require looks like:
TableWorker
is just a variable name I used for table.js'sexport default class Table {...}
. Thename=tableRoller
specifies the generated outputted[name].worker.js
filename. For example, I have another WebWorker nameddistCalc.worker.js
, so myimport
looks like:Note that in this case,
distWorker
only ever runs in a WebWorker, whileTable
is used in both mymain.js
entry point and mytableRoller.worker.js
WebWorker file.workerjs
andworker-loader
generate a new entry point file and pull in all of the dependencies of those classes. Tobias Koppers (worker-loader) and Eugene Ware (workerjs) are geniuses.Detecting WebWorker
My
_inWebWorker
detection is: