Web worker setup that (mostly) works



  • With many thanks to @qyloxe for this thread, I went into the rabbit hole of trying to get web workers functioning in my quasar project. It was important to me to have HMR working, and to be able to pass data back and forth between main thread and web worker. After failing with many libraries and techniques (comlink, comlink-loader, workerize-loader, greenlet, etc) I settled on a modified procedure inspired from this page.

    Here are the steps I needed to take to make this work:
    1: npm install -D worker-plugin
    2: configure quasar.conf.js with the following (simplified with just the additions you need, there are many other declarations in this file that are unrelated to this):

    const WorkerPlugin = require('worker-plugin')
    module.exports = function (/* ctx */) {
      return {
        // Full list of options: https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-build
        build: {
          chainWebpack (chain, { isServer, isClient }) {
            chain.output.set('globalObject', 'this')
          },
          extendWebpack (cfg) {
            cfg.plugins.push(new WorkerPlugin()),
            cfg.module.rules.push({
              enforce: 'pre',
              test: /\.(js|vue)$/,
              loader: 'eslint-loader',
              exclude: /node_modules/
            })
          }
        }
      }
    }
    

    3: create a folder with the name of your worker somewhere under src: my-project/src/my-worker
    4: under this folder (my-worker in my case) create an index.js file with the following:

    const worker = new Worker('./myWorker.worker.js', { type: 'module' });
    
    const send = message => worker.postMessage({
      message
    })
    
    export default {
      worker,
      send
    }
    

    5: in the same folder create your worker file (myWorker.worker.js) and populate it with the following:

    addEventListener('message', async (event) => {
      console.log('data received:', event.data)
      // do whatever you want here to transform your data
      postMessage(event.data) // just posting back to main the data we received in this case
    })
    

    6: Use your worker in one of your vue files to send and retrieve info:

    <script>
    import myWorker from './my-worker'
    export default {
      data () {...},
      mounted () {
        myWorker.send(someObject) // sending my object to the worker   
        myWorker.worker.onmessage = event => {
          console.log('status returned:', event.status)
          console.log('data returned:', event.data)
        }
      }
    }
    </script>
    

    7: VERY IMPORTANT (at least in my setup). I had to add the path to my worker file (src/my-worker/myWorker.worker.js) inside my .eslintignore file at the root of my project, or there were all kinds of errors and this would not work.

    From here you can send and receive whatever you want to your worker, and have these operations happen off thread. And when you make changes to the file, HMR seems to reload them much better than other setups and does not require me to restart the quasar dev server (although on occasion I do have to force refresh my browser page to pickup changes, but that is minor in comparison).

    Hope this helps others who have been struggling to make this work in quasar.


Log in to reply