Web-workers in Create React App (CRA) without unmounting

nicolasrannou

Nicolas Rannou

Posted on March 26, 2020

Web-workers in Create React App (CRA) without unmounting

There are a lot of great options available when it comes to using web-workers in your web-app. Unfortunately, it can be challenging to use in a Create React Application (CRA) without un-mounting your application.

In this article, we share my journey of using web-workers in CRA (without un-mounting!)

Table of contents generated with markdown-toc

Why not unmounting?

  • Webpack configuration can be overwhelming
  • It can be difficult to upgrade to the next version of react-scripts
  • CRA team will not help us if something goes side-ways

Finding the right tools for YOU

The right tool for me would check the items in the following list:

  • Must: Not unmounting CRA
  • Must: Support transferable objects
  • Nice to have: Easy to use
  • Nice to have: Typescript support
  • Nice to have: Pooling system

Attempt 1: Threads.js

Threads.js looked very promising and feature complete (according to my requirements).

However, to use it within webpack, you must use its companion loader (threads-plugin).

That means you must access the webpack configuration file and add the loader there. That was a no-go for me because it implies un-mounting CRA.

Attempt 2: Workarize

The next step was to find a tool that leverages webpack loaders rather than plugins. With webpack loaders, we can inline the loader in the import statement, therefore, we do not need to modify the webpack configuration file to use it.

\\ inline the loader in the import statement
import {Something} from 'my-loader!./utils/filename'

workarize and its workarize-loader seemed pretty cool. Although it doesn't support pooling the API looked awesome and super intuitive.

But it doesn't support transferable objects at the time I write this post (03-26-2020), so that was another no-go.

Attempt 3: Worker-loader

Next, I tested worker-loader and its transferable objects.

It worked fine but using web-workers without sugar on top just didn't feel right for me - we can do better!

Attempt 4: Comlink

Then comes comlink. It "makes WebWorkers enjoyable again" (to quote their README).

comlink works nicely with the worker-loader and adds this nice touch on top of the web-workers to make it easy to use.

It may provide features you do not need but works fine in my experience (so far 🤞).

It also works well with Typescript.

It doesn't support pooling but I can live with that!

How it looks

\\ main.ts
import * as Comlink from 'comlink';
/* eslint-disable import/no-webpack-loader-syntax */
import Worker from 'worker-loader!../util/worker';

async function init() {
  const worker = new Worker();
  const obj = Comlink.wrap(worker);
  await obj.inc();
}
init();

\\ worker.ts
import * as Comlink from 'comlink';

const obj = {
  counter: 0,
  inc() {
    this.counter++;
  }
};

Comlink.expose(obj);

That's it

Each tool that was tested is great and you should really consider what you are looking for before making an informed decision.

I can live without pooling as long as it is enjoyable to work with the web-worker so that's why I chose comlink.

TLDR:

  • ✅Must: Not unmounting CRA
  • ✅Must: Support transferable objects
  • ✅Nice to have: Easy to use
  • ✅Nice to have: Typescript support
  • 🔴Nice to have: Pooling system

Thanks for reading!

💖 💪 🙅 🚩
nicolasrannou
Nicolas Rannou

Posted on March 26, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related