souporserious

Bundling Web Workers for NPM

2 min read

You might have heard that JavaScript is single-threaded. In short, this means code executes synchronously, and we can only do a max amount of work in the browser before things can start to feel laggy. Enter web workers; this browser API gives us a way to offload computational work to a background thread, freeing up the main thread to stay performant.

When working in a simple web stack, workers are pretty straightforward to work with, as seen in the MDN docs. However, in our modern era, we’re most likely using a build system in possibly a sandboxed environment or wanting to distribute our code on a package manager like NPM.

Workerize

This is where workerize comes to the rescue. This excellent lightweight library by Jason Miller makes bundling web workers an absolute breeze!

1const worker = workerize(`
2const canvas = new OffscreenCanvas(0, 0)
3const context = canvas.getContext('2d')
4export function getTextWidth(text) {
5 return context.measureText(text).width
6}
7`)
8worker.getTextWidth('Measure This Text').then((textWidth) => {
9 console.log(textWidth)
10})

No Magic Just Brilliance

You might be wondering how this magic works. It turns out to be a pretty simple solution. The function takes a template literal, converts it to a blob, and loads it in as if the worker was a file we requested using createObjectURL. Brilliant!

Syntax Highlighting & Formatting

While this library is great, it comes with tradeoffs since we need to write our worker in a string. Depending on how complex it is, this can become tedious since we lose out on text highlighting and formatting with Prettier.

Not to worry, we can utilize yet another library to fix this. The raw.macro library can load a file as a string at build time, allowing us to retain text highlighting and formatting!

1import workerize from 'workerize'
2import raw from 'raw.macro'
3const workerString = raw('./worker.js')
4const worker = workerize(workerString)

Summary

Workers can free up the main thread when doing heavy work like text measuring, but can seem impossible to bundle with a package manager. In this post, we looked at how we can easily bundle our workers using the workerize library and even restore the developer experience so we get the best of both worlds!

Updated:
  • development
  • performance
Previous post
Getting Started with Figma Webhooks
Next post
Bringing SwiftUI Stacks to the Web