question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Is it possible to use load webworkers?

See original GitHub issue

In the past I’ve used the web-worker loader in webpack, but with create-react-app, I get the no-webpack-loader-syntax error.

Is there another way that you recommend to do this? I can’t find anything in your documentation about webworkers, and it seems there isn’t another way to load them in webpack.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:15
  • Comments:24 (6 by maintainers)

github_iconTop GitHub Comments

17reactions
speicuscommented, Oct 31, 2017

Okay, if anyone stumbles upon this thread, here’s a bit messy, but quick and easy way to get WebWorkers working.

UPDATE. As create-react-app continues to update its webpack confuguration, the code below will need updates as well. Specifically, the part which locates babel-loader configuration (const babelLoader = ...). Check getBabelLoader() from https://github.com/timarney/react-app-rewired/blob/master/packages/react-app-rewired/index.js to get an updated version of the code in question.

  1. Install react-app-rewired, worker-loader and lodash (the latter is here just for the sake of cloneDeep — feel free to replace it with anything you like) : npm install --save-dev react-app-rewired worker-loader lodash
  2. Create config-overrides.js file in the root directory of your application:
const lodashCloneDeep = require('lodash/cloneDeep');

module.exports = function override(config, env) {
    // Add worker-loader by hijacking configuration for regular .js files.

    const workerExtension = /\.worker\.js$/;

    const babelLoader = config.module.rules.find(
        rule => rule.loader && rule.loader.indexOf('babel-loader') !== -1
    );

    const workerLoader = lodashCloneDeep(babelLoader);

    workerLoader.test = workerExtension;
    workerLoader.use = [
        'worker-loader',
        { // Old babel-loader configuration goes here.
            loader: workerLoader.loader,
            options: workerLoader.options,
        },
    ];
    delete workerLoader.loader;
    delete workerLoader.options;

    babelLoader.exclude = (babelLoader.exclude || []).concat([workerExtension]);

    config.module.rules.push(workerLoader);

    // Optionally output the final config to check it.
    //console.dir(config, { depth: 10, colors: true });

    return config;
};
  1. Create workers by naming them MySomething.worker.js:
import myDoSomething from 'my-do-something';

onmessage = async function (message) { // eslint-disable-line no-undef
    console.log('Message received from main script', message.data);
    const workerResult = await myDoSomething(message.data);
    console.log('Posting message back to main script');
    postMessage(workerResult);
};
  1. Create instances of your worker:
import MySomethingWorker from './MySomething.worker.js';

const worker = new MySomethingWorker();
  1. Enjoy webworkers, stored separately from the main bundle (or inline — check worker-loader options) while being processed by Babel. 😃

P.S. As a sidenote, a bit of feedback, as I’ve just began experimenting with create-react-app (having always created my own configurations before). I must say it feels that it kind of lost the second part of “convention over configuration” principle. That is, it almost entirely discarded the ability “to specify unconventional aspects of the application”. For example, I had to install the aforementioned react-app-rewired just to get my own module resolve paths and LESS support — being unable to configure such basic things was quite a surprise.

9reactions
danielpoxcommented, Nov 19, 2017

Based on the previous answers, I wrote a helper class to make things a bit easier when working with Web Workers in React.

The helper class looks like so:

// WebWorker.js

export default class WebWorker {
    constructor(worker) {
        let code = worker.toString();
        code = code.substring(code.indexOf("{") + 1, code.lastIndexOf("}"));

        const blob = new Blob([code], { type: "application/javascript" });
        return new Worker(URL.createObjectURL(blob));
    }
}

Then, you write your worker code like this:

// MyWorker.js

// @args: You can pass your worker parameters on initialisation
export default function MyWorker(args) {
    let onmessage = e => { // eslint-disable-line no-unused-vars
        // Write your code here...
        
        postMessage("Response");
    };
}

To create a Web Worker instance, write like so:

// App.js

// WebWorker helper class
import WebWorker from './utils/WebWorker';
// Your web worker
import MyWorker from './MyWorker';

// Worker initialisation
const workerInstance = new WebWorker(MyWorker);
const workerInstanceWithParams = new WebWorker(new MyWorker("foo"));

// Communication with worker
workerInstance.addEventListener("message", e => console.log(e.data), false);
workerInstance.postMessage("bar");

Using this method, you simply utilise the WebWorker helper class, and there’s no need for Webpack loaders or anything like that. It worked for me and solved my problems. Hopefully we won’t have to do workarounds like these in the future.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using Web Workers - Web APIs - MDN Web Docs
Web Workers are a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering ......
Read more >
Is there some kind of load event for web-workers?
As per last comment, I'll wrote my suggestion as answer: You can make the worker emit a message when they're loaded, and you...
Read more >
Optimized media loading using the Web Workers API
The Web Workers API helps to solve the decades-old issue of efficiently loading media into JavaScript-based web applications.
Read more >
Understanding and Using Web Workers - CODE Magazine
A Web Worker script is loaded on demand, at run-time. Unlike other JavaScript files with which you've worked in the past that have...
Read more >
Loading web workers using Webpack 5 · mmazzarolo.com
worker-loader is the pre-webpack-5 way to load web workers, ... you won't be able to load the following web worker: const myWorker =...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found