- Vue CLI 3 (see https://cli.vuejs.org for installation instructions)
worker-loaderto let Webpack load the worker for youpromise-workerto simplify communication with the worker
This example uses the standard Vue CLI 3 commands:
yarn serveyarn buildYou could use Python's SimpleHTTPServer to check out the build locally:
cd dist
python -m SimpleHTTPServervue create minimal-vue-worker
# select your preferred preset, such as 'default'
cd minimal-vue-workeryarn add --dev worker-loader promise-workerSetting globalObject to this to fix a reference error: "Uncaught ReferenceError: window is not defined".
Note: This is a workaround taken from webpack/webpack#6642 (comment) and should be replaced by
target: 'universal'when webpack/webpack#6525 has been implemented.
module.exports = {
chainWebpack: config => {
config.output
.globalObject('this')
/* ... */
}
}For HMR there's currently an issue in Safari which can be fixed with a small config change:
module.exports = {
chainWebpack: config => {
/* ... */
if (process.env.NODE_ENV === 'development') {
config.output
.publicPath('/')
.filename('[name].[hash].js')
.end()
}
/* ... */
}Configuring the worker-loader here using a rule does not work reliably.
- Hot Module Replacement does not seem to work at all
- Even refresh (F5) doesn't reload the worker javascript, unless the development server is restarted
- Sometimes the contents of
index.htmlis served in stead of the worker javascript!
Using the inline loader syntax works fine:
import Worker from 'worker-loader!./worker'But if it did work, I would need to add the following configuration here, which triggers the loader for any file ending with worker.js. You can't use this in combination with the inline syntax.
module.exports = {
chainWebpack: config => {
/* ... */
config.module
.rule('worker')
.test(/worker\.js$/)
.use('worker-loader')
.loader('worker-loader')
.end()
/* ... */
}
}mkdir src/my-worker
touch src/my-worker/index.js
touch src/my-worker/worker.jsThis is slightly opinionated, but the idea is this: the index.js defines the public API of your worker, and worker.js defines the private API. The index.js offers a thin layer of abstraction to simplify communication with the worker.
Note: Take care that the
worker.jsdoes not import anything major from the main application, especially when you're refactoring an existing code base. You don't want to duplicate your entire app inside your worker...
This is the script the rest of your application sees. It sets up the postMessage and onMessage code, and exports a simple API.
import PromiseWorker from 'promise-worker'
import Worker from 'worker-loader!./worker'
const promiseWorker = new PromiseWorker(new Worker())
const send = message => promiseWorker.postMessage({
type: 'message',
message
})
export default {
send
}This is where messages come in and are passed on to other modules if you like.
Promise-Worker makes all this really simple and intuitive, and if you like you can still access the raw Web Worker API, i.e. postMessage and onMessage.
import registerPromiseWorker from 'promise-worker/register'
registerPromiseWorker((message) => {
if (message.type === 'message') {
return `Worker replies: ${JSON.stringify(message)}`
}
})In any part of your application where you want to use the worker, do something like this:
import myWorker from '@/my-worker'
/* ... */
myWorker.send({ anything: 'you need' })
.then(reply => {
// Handle the reply
})