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!
Top comments (8)
I had to use the defenition of "typings/custom.d.ts" from stackoverflow.com/questions/613825...
Thanks for a very useful and informative blog post!
It works nicely when I use one WebWorker! However, if I try to use more than one WebWorker in my codebase, I get two errors at compile time:
Did you experience this as well and if so, were you able to resolve the problem?
Sorry - I'm a bit confused - am trying to use comlink with my create-react-app and not ejecting. But I think you're missing steps? I installed both comlink and worker-loader, but just using the code above in option 4 doesn't work. I modified my worker-loader import to point to my worker.js, but that is showing issues that it can't find needed modules (e.g. webpack/lib/node/NodeTargetPlugin". Can you please elaborate the specific setup steps?
Thank you for the great blog post!
FYI: The link in the TLDR for transferable objects is broken.
We're over a year out from you writing this but it helped me today on a project I'm helping build for a friend's dissertation. Thank you!
I think you meant don't eject the app, not unmount. Thanks for list all these projects. I didn't know about comlink. Have to try
what do you mean by "It doesn't support pooling"? thanks!
Another option is to use someting like Rescripts to customise WebPack configuration without ejecting CRA.