DEV Community

Evan Winter
Evan Winter

Posted on • Updated on

Use Web Workers in a Gatsby project

Update Feb. 2022 – This probably doesn't work anymore... I haven't worked on a Gatsby project in a while. I'll try to find some time to revisit this and get it working again.

Introduction

Have a CPU-intensive task that's blocking your UI? Do you want to offload it to a background thread using a Web Worker? Here's how it's done in the context of a Gatsby project.

I came across this approach in a GitHub issue, and decided to write it up here for anyone else looking for the same solution.

Install dependencies

Install workerize-loader:

npm install --save workerize-loader # or yarn add workerize-loader
Enter fullscreen mode Exit fullscreen mode

Add workerize-loader to Webpack bundle

Now, we need to inject our workerize-loader configuration into the Webpack bundle generated by Gatsby.

To do so, add the following code to gatsby-node.js:

exports.onCreateWebpackConfig = ({ actions: { replaceWebpackConfig }, getConfig }) => {
  const config = getConfig()

  config.module.rules.push({
    test: /\.worker\.js$/,
    use: { loader: 'workerize-loader' }
  })

  config.output.globalObject = 'this'

  replaceWebpackConfig(config)
}
Enter fullscreen mode Exit fullscreen mode

This code gets the current Webpack config generated for us by Gatsby, and adds the workerize-loader rule which finds files with a .worker suffix and processes them as Web Workers.

Create a worker file

Create a file with a .worker suffix, like so:

// expensive.worker.js
export function doExpensiveTask(num) {
  let result = 0
  for (let i = 0; i < Math.pow(num, 10); i++) {
    result += result / i
  }
  return result
}
Enter fullscreen mode Exit fullscreen mode

Usage

Now, you can import it and use it like a normal function.

import MyWorker from "path/to/expensive.worker.js"

const result = MyWorker.doExpensiveTask(5)
Enter fullscreen mode Exit fullscreen mode

Bonus: Async Example

// expensive-async.worker.js
export async function doExpensiveAsyncTask() {
  const url = "https://jsonplaceholder.typicode.com/todos/1"
  return await fetch(url)
}
Enter fullscreen mode Exit fullscreen mode
import MyAsyncWorker from "path/to/expensive-async.worker.js"

const result = await MyAsyncWorker.doExpensiveAsyncTask()
Enter fullscreen mode Exit fullscreen mode

Latest comments (2)

Collapse
 
4sight profile image
Peter

This worked well, and it was straightforward to integrate with typescript. Thanks

Collapse
 
niclaslovdahl profile image
Niclas Lövdahl

Do you have a working example of this? Can't get it working.