Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't use Worker-Loader with Vuejs and Webpack

I am trying to get web workers up and running with Vue cli3 and I'm having trouble getting it to work.

I want to use the following package, worker-loader (and not vue-worker), as it looks well maintained and with more contributions.

Following their tutorial I attempted to modify webpack using the vue cli as follows:

module.exports = {
    chainWebpack: config => {
        config.module
          .rule('worker-loader')
          .test(/\.worker\.js$/)
          .use('worker-loader')
            .loader('worker-loader')
            .end()
    }
}

which I hope should match their

{
  module: {
    rules: [
      {
        test: /\.worker\.js$/,
        use: { loader: 'worker-loader' }
      }
    ]
  }
}

which can be read here (https://github.com/webpack-contrib/worker-loader). I tried to follow the documentation for vue cli3 as best I could (found here: https://cli.vuejs.org/guide/webpack.html#simple-configuration).

My component is pretty simple:

import Worker from 'worker-loader!./../../sharedComponents/equations/recurringTimeComposer.js';

<...>
watch:{

 recurringPaymentReturnObj: function(newVal, oldVal){
        const myWorker = new Worker;
        myWorker.postMessage({ hellothere: 'sailor' });
        myWorker.onmessage = (e) => {
            console.log('value of e from message return', e.data);
 }
}
<...>

and in my ./../../sharedComponents/equations/recurringTimeComposer.js file I have:

onmessage = function(e) {
    console.log('Message received from main script: ', e.data);
    // var workerResult = 'Result: ' + e.data;
    // console.log('Posting message back to main script');
    postMessage('hello back handsome');
    close();
}

I keep getting the error message:

ReferenceError: window is not defined a162426ab2892af040c5.worker.js:2:15

After some googling I came across this post: https://github.com/webpack/webpack/issues/6642, which suggests that the best way to fix this is to add the following to webpack:

output: {
       path: path.join(__dirname, 'dist'),
       filename: 'bundle.js'
       publicPath: 'http://localhost:3000',
       globalObject: 'this'
},

After modifying my vue.config.js file I have:

module.exports = {
    chainWebpack: config => {
        config.module
          .rule('worker-loader')
          .test(/\.worker\.js$/)
          .use('worker-loader')
            .loader('worker-loader')
            .end()
        config
            .output
            .path(path.join(__dirname, 'dist'))
            .filename('bundle.js')
            .publicPath('http://localhost:8080')
            .globalObject('this')
    }
}

...but still I am getting the window is not defined error.

Does anyone know what is going wrong? It seems to be a weird error in webpack.

Thanks!

EDIT: oh yeah, here is the MDN page for webworker as well: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers.

like image 203
Peter Weyand Avatar asked Aug 29 '18 21:08

Peter Weyand


2 Answers

This works for me (note the first line):

config.module.rule('js').exclude.add(/\.worker\.js$/)

config.module
  .rule('worker-loader')
  .test(/\.worker\.js$/)
  .use('worker-loader')
  .loader('worker-loader')

The first line excludes worker.js files, so two loaders wouldn't fight over the same js file

like image 177
alt146 Avatar answered Oct 25 '22 09:10

alt146


Being new to Javascript I kept coming back to this issue when trying to use web workers with VueJS. I never managed to make it work with vue-worker or worker-loader.

It is now 2020 and Google has released worker-plugin.

To use it create a module my-worker with two files index.js and worker.js.

index.js creates the module:

const worker = new Worker('./worker.js', { type: 'module' });

const send = message => worker.postMessage({
  message
})

export default {
  worker,
  send
}

worker.js contains the logic:

import _ from 'lodash'
addEventListener("message", async event => {
    let arrayToReverse = event.data.message.array
    let reversedArray = _.reverse(arrayToReverse)
    // Send the reversed array
    postMessage(reversedArray)
});

You will also need to update your vue.config.js to use the WorkerPlugin:

const WorkerPlugin = require('worker-plugin')
module.exports = {
  configureWebpack: {
    output: {
      globalObject: "this"
    },
    plugins: [
      new WorkerPlugin()
    ]
  }
};

Now you can use you worker in your components:

  1. Import it with import worker from '@/my-worker'.
  2. Setup a listener in the mounted() lifecycle hook with worker.worker.onmessage = event => { // do something when receiving postMessage }
  3. Start the worker with worker.send(payload).

I set up a starter code on github. I still haven't managed to make HMR work though...

like image 32
braincoke Avatar answered Oct 25 '22 07:10

braincoke