Web workers - how to use in Quasar



  • There’s many libs for web workers. One which is quite simple and working in Quasar is described below.

    Lets create a new test Quasa project, with javascript and simple options:

    quasar create qworkers
    

    We will be using this library and integrate it with our test project:
    https://github.com/developit/workerize-loader

    In file package.json we will add this:

      "devDependencies": {
        ...
        "workerize-loader": "^1.3.0"
      },
    
    

    In file quasar.conf.js we will add this:

        build: {
          ...
          // https://quasar.dev/quasar-cli/handling-webpack
          chainWebpack (chain) {
            chain.output.set('globalObject', 'this')
          },
          extendWebpack (cfg) {
            ...
            cfg.module.rules.push({
              test: /\.worker\.js$/,
              exclude: /node_modules/,
              loader: 'workerize-loader',
              options: { inline: true }
            })
          }
        },
    

    Our index.vue should look like this:

    <template>
      <q-page class="flex flex-center">
        <img
          alt="Quasar logo"
          src="~assets/quasar-logo-full.svg"
        >
        <q-btn @click="start1">start worker</q-btn>
        <q-btn @click="start2">start DOM function</q-btn>
      </q-page>
    </template>
    
    <script>
    import worker from './test.worker'
    
    export default {
      name: 'PageIndex',
      methods: {
        async start1 () {
          const instance = worker()
          const count = await instance.expensive(5000)
          console.log(`Ran1 ${count} loops`)
        },
        expensive (time) {
          const start = Date.now()
          let count = 0
          while (Date.now() - start < time) {
            count++
          }
          return count
        },
        start2 () {
          const count = this.expensive(5000)
          console.log(`Ran2 ${count} loops`)
        }
      }
    }
    </script>
    

    We will add a new file src/pages/test.worker.js with content:

    export function expensive (time) {
      const start = Date.now()
      let count = 0
      while (Date.now() - start < time) {
        count++
      }
      return count
    }
    
    export default expensive
    

    Next we execute commands:

    npm install
    quasar dev
    

    And the browser should popup:

    dcdbeb92-5703-476c-85fe-a2979fe8bdf9-image.png

    Pressing “start worker” button will execute CPU expensive function in web worker. Observe, that the page is fully responsive. The result will be shown in the console.
    Pressing “start dom function” will execute CPU expensive function in main DOM browser thread. The page will NOT be responsive! The result will be shown in the console.

    Discussion:

    1. Why this library? Well, it’s simple and it works. The integration by webpack in inline mode allows nice HMR and quasar bundling.
    2. Why there are strange CSP comments in firefox? Yes, the web workers has some security quirks and there are differences in handling them in Chrome and Firefox. There is a section about Content Security Policy in MDN about that:
      https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
    3. Why do you need web workers in Quasar? In Quasar there are many potential optimizations which could benefit from using web workers. They are not only typical sorting, filtering, querying but even less obvious parts of Quasar component where the CPU work could be transferred to web worker. Yes, it could make Quasar the fastest framework in the market.
    4. Oh, but I’m just a user and I want web workers in Quasar, too! Well, I would like also! I think it is time to include web workers support in base library - similar as it was done with support for other browser API as local storage, full screen, resize. The one, working Quasar interface to web workers would be a game changer.
    5. What if somebody will create an App Extension with web workers support instead? This IMHO would be less optimal, because the Quasar API for web workers should be the same for internal Quasar components and for user apps. The example above is rather simple in terms of communication, but in real life, probably one would want a more advanced communnication between components. It comes to mind the excellent BEX mode and the concept of bridge. I think, if Quasar would implement support for web workers, the existing bridge concept as a means of communication would be just right.


  • @qyloxe

    Obviously amazing! a few question:

    1. Is it possible/useful to offload heavy UI components (with render functions i Quess) to workerize-loader?

    2. can you use Quasar current workbox webworkers( for install to deceive, auto updating, cache, offline support ect) and workerize-loader at the same time?



  • @dobbel said in Web workers - how to use in Quasar:

    @qyloxe
    Obviously amazing! a few question:

    1. Is it possible/useful to offload heavy UI components (with render functions i Quess) to workerize-loader?

    YES! q-table filtering, q-tree node searching and much, much more could be optimized by web workers.

    1. can you use Quasar current workbox webworkers( for install to deceive, auto updating, cache, offline support ect) and workerize-loader at the same time?

    workbox uses “service workers” we are using something different “web workers”. More here:

    https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API

    There are more types of workers also.



  • @qyloxe

    Ah that’s something I did not know about workers. Thanks

    Would it be possible/feasible to have the offloading of ‘expensive’ code be (auto)managed by Vue or Quasar? For example: offloading the entire template (UI) rendering process (in maybe multiple webworkers)?

    I am all excited 🙂



  • @dobbel said in Web workers - how to use in Quasar:

    @qyloxe

    Would it be possible/feasible to have the offloading of ‘expensive’ code be (auto)managed by Vue or Quasar? For example: offloading the entire template (UI) rendering process (in maybe multiple webworkers)?

    well, web workers does not have access to DOM, so it’s tricky. There are projects like this:

    https://github.com/ampproject/worker-dom

    BUT i think it should be done (in most cases) at the Vue level not Quasar. At the Quasar level, there’s possibility to use worker threads for many, many cpu intensive tasks. AND it should be possible, to use workers in user apps easily in Quasar framework.



  • @qyloxe

    Thanks for the info. I have fiddled with that worker-dom project. Have you ever used it in a Quasar project?



  • There’s a web worker wrapper out there for Vue, called vue-worker.



  • @dobbel said in Web workers - how to use in Quasar:

    @qyloxe

    Thanks for the info. I have fiddled with that worker-dom project. Have you ever used it in a Quasar project?

    Nope. I mentioned it as an idea or possibility of DOM accessibility from web workers. Anyway, worker-dom abstraction works rather at the vue (or react, or svelte) level than at the Quasar. IMHO such interface from workers should be available as another browser API.

    I will be needing in the near future a massive boost in CPU processing in Quasar, so I’m looking for a way to deal with that. The web worker is OK in terms of user experience, but I’m afraid, that the real performance boost will need the WASM technology. Nevertheless, using web workers at the Quasar level would be so much cool!



  • @metalsadman said in Web workers - how to use in Quasar:

    There’s a web worker wrapper out there for Vue, called vue-worker.

    Yeah, I saw that and this is what took my attention:

    • the last commit is from three years ago - deal breaker 😞
    • it is a simple API wrapper, the functions are mostly inlined so this will be a problem in Quasar apps or bigger projects
    • the model of communication is actually mimicking the web workers API so there’s no real gain. I would prefer to have something like RPC (as in workerize-loader) or the adjusted model of processing with external message bus - strongly similar to BEX and bridge in Quasar
    • I need to have HMR, debuggability and easy bundling of workers with tree shaking. I’m afraid that interfacing vue-worker with Quasar could be tricky.

    The workerize-loader took my attention because of webpack. This is a fun idea! I was very curious if it will work with Quasar and I’m happy that it is.



  • I can’t seem to make this work in my own code. I have every part setup, imported and making the call without error, but it returns “undefined”, even if the only thing the function does is return 'something'…Any advice?



  • @qyloxe and what about testing with Jest, for example??
    This solution workerize-loader will work out-of-box with unit test ? If it won’t, how to make it work in a testing scenario ?
    Sometime we forget about testing and complexities the solutions for our code brings when testing the codebase.



  • after working with it further, it seems related to trying to import axios into the worker file, if I leave that out, I can indeed call it and return 'something'…Any tips for making an axios or fetch call from inside the worker?



  • @qyloxe Another problem I am having is that I have to fully restart quasar dev after every change to my worker file. Hot reloading is happening, but no changes are being picked up…any suggestions there? Thanks!



  • @ssuess

    Here is some info about that might help:
    https://quasar.dev/quasar-cli/developing-pwa/hmr-for-dev



  • @dobbel thanks…but does this apply to web workers as well as service workers? Plus my browser cache is disabled and I am running in SPA mode



  • @ssuess

    but does this apply to web workers as well as service workers?

    I don’t know…

    Instead of restarting you could try clearing the site data every time you change the worker file in chrome and then (hard) reload… not ideal but could be faster then app restart.

    chrome dev tools -> application > application > Clear storage -> Clear site data



  • @ssuess said in Web workers - how to use in Quasar:

    @qyloxe Another problem I am having is that I have to fully restart quasar dev after every change to my worker file. Hot reloading is happening, but no changes are being picked up…any suggestions there? Thanks!

    Yeah, we are just clearing the path with web workers in Quasar. And even Vue. It is advanced technology, magical even, so we will have problems with debugging, testing, developing. I consider web workers as a browser technology not meant for general public, hence the mischievous support between browsers, mystic documentation and labyrinthical code samples. BUT if one will master the obstacles, and build something working in another browser thread, I assume one would achieve … OK I don’t know what will be achieved, because I haven’t achieved it myself ha ha

    Anyway, this is a start. I would VERY much want to have a web workers support in Quasar, BUT i do know, that it is a BIG task. So, my proposal is to just include some web workers support in the most data intensive components (q-table, q-tree, etc), and go from there. In the process we will probably learn how to test them, debug them and live with them. What I wanted to achieve with this post, is to create a hunger for inclusion of web workers in Quasar framework 🙂



  • Something I just discovered that solves the reload problem for me:

    build: {
      parallel: false,
      ...
    }
    

    Set this and now when I make changes to my worker.js file, it will properly reload without restart.



  • @ssuess nice!



  • I wish it was nice, but it only kinda sorta sometimes seems to have an effect. I have wasted most of today trying to get web workers to play nice with quasar, and it has been a bust. There are many issues with this (at least for me):

    1. Random failures to compile. The exact same code will compile and run fine once, then another time not
    2. Missing/non existent/ or useless errors such as failed to compile with 0 errors, so kinda impossible to debug
    3. Exceedingly difficult to configure with quasar.config.js. I have tried chaining, I have tried pushing rules, I have tried comlink, comlink-loader, workerize, worker-loader…none of it works very well. Just when I think I have it working, it fails suddenly.
    4. I can’t find any docs on the web that really fit the use case of quasar with web workers.
    5. The sometimes HMR works, sometimes not dilemma

    Giving up for today. Maybe tomorrow will be luckier.


Log in to reply