Skip to content

feat(js): Update web worker guide with new webWorkerIntegration APIs #14395

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 112 additions & 44 deletions docs/platforms/javascript/common/best-practices/web-workers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,7 @@ sidebar_order: 9000
supported:
- javascript
notSupported:
- javascript.angular
- javascript.cordova
- javascript.electron
- javascript.ember
- javascript.gatsby
- javascript.nextjs
- javascript.nuxt
- javascript.react
- javascript.solid
- javascript.solidstart
- javascript.vue
- javascript.wasm
- javascript.node
- javascript.aws-lambda
- javascript.azure-functions
Expand All @@ -29,28 +18,22 @@ notSupported:
- javascript.hono
- javascript.koa
- javascript.nestjs
- javascript.tanstackstart-react
- javascript.deno
- javascript.cloudflare
- javascript.bun
---

Sentry's Browser SDK supports [Web Workers API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API). To capture unhandled errors from Web Workers:
Sentry's Browser SDK supports the [Web Workers API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API).
You can use the SDK in different ways, though we recommend initializing it in the main thread to capture unhandled errors from workers automatically.

Install `@sentry/browser` using your package manager:
## Recommended Setup

```bash {tabTitle:npm}
npm install @sentry/browser --save
```

```bash {tabTitle:yarn}
yarn add @sentry/browser
```
_Available since_ : 9.40.0

```bash {tabTitle:pnpm}
pnpm add @sentry/browser
```

Then you can use it:
To capture unhandled errors from Web Workers, initialize Sentry in your application code that runs on the main thread
and let the SDK know about the web worker:

```javascript {filename:index.js}
```javascript {filename:index.js} {1-5,9-10}
import * as Sentry from "@sentry/browser";

Sentry.init({
Expand All @@ -59,34 +42,75 @@ Sentry.init({

const worker = new Worker("worker.js");

// Add the integration before listening to worker messages
Sentry.addIntegration(Sentry.webWorkerIntegration({ worker }));

worker.onmessage = (event) => {
// ...
}
```

Then, establish communication between the worker and the SDK:

```javascript {filename:worker.js}{1-4}
import * as Sentry from "@sentry/browser";

// Call this before posting any message
Sentry.registerWorker({ self })

// Errors from `onmessage` callback of `worker.js`
// will be captured.
worker.postMessage("Hello!");
// will be captured automatically.
self.postMessage("Worker ready!");
self.onmessage = (event) => {
// ...
}
```

<Alert level="warning" title="Manual Capturing">
<Alert level="warning" title="The Order Matters">

To capture errors or messages manually, such as to use `captureMessage` or `captureException` inside Web Workers, Sentry should be initialized inside each Web Workers' own scope. Only unhandled errors will be captured and sent to Sentry without worker-level initialization.
Ensure that in both, your main thread code as well as the worker, you set up Sentry before you start listening to messages.
The Sentry SDK sends messages from the worker to the main thread, so if you start listening before Sentry is initialized,
the messages will appear in your listeners and you have to handle them manually.

</Alert>

#### Usage Without Worker-Level Initialization
### Multiple Workers

The `sentryWebWorkerIntegration` supports registering multiple workers.
You can add them directly, when you initialize the integration, or later on.
This is helpful, if you have workers that are initialized at different points in time in your application lifecycle.

```javascript {filename:worker.js}
```javascript {filename:index.js} {1-5, 10-14, 18}
import * as Sentry from "@sentry/browser";

self.onmessage = (message) => {
// This will fail silently.
Sentry.captureMessage("Message received");
Sentry.init({
dsn: "___PUBLIC_DSN___",
});

// This error will be captured.
throw new Error();
};
const worker1 = new Worker("worker.js");
const worker2 = new Worker("worker2.js");

// Multiple workers can be added directly:
const webWorkerIntegration = Sentry.webWorkerIntegration({ worker: [worker1, worker2] });
Sentry.addIntegration(webWorkerIntegration);

// or later on:
const worker3 = new Worker("worker3.js");
webWorkerIntegration.addWorker(worker3);
```

#### Usage With Worker-Level Initialization
<Alert level="warning" title="Keep in Mind">

- Every worker must call `Sentry.registerWorker({ self })` to register itself with the SDK.
- Do not call `Sentry.webWorkerIntegration()` multiple times! This will lead to unexpected behavior.

</Alert>

## Manually Capturing Errors

```javascript {filename:worker.js}
To capture errors or messages manually, via `Sentry.captureMessage` or `Sentry.captureException` inside Web Workers, you can also import the SDK in the worker and initialize it.

```javascript {filename:worker.js} {1-5,9}
import * as Sentry from "@sentry/browser";

Sentry.init({
Expand All @@ -102,10 +126,54 @@ self.onmessage = (message) => {
};
```

Note that initializing the SDK in the worker **completely decouples** it from the SDK running on the main thread.
This means that data like user, tags, traces or scope data set on either side will not be shared with the other side.

Sometimes, this is the better approach, for instance if you develop a worker that is used in arbitrary applications.
Other times, if the worker is just part of your application, you likely want to use the [SDK from the main thread](#recommended-setup).

<Alert level="warning" title="Keep in Mind">

If you initialize the SDK in the worker, don't use the `Sentry.webWorkerIntegration` to register the worker.
Likewise, don't use the `Sentry.registerWorker` in the worker. Both methods are only supposed to be used when relying on the SDK [from the main thread](#recommended-setup).

</Alert>

### Integrations

Note, that if you use non-default integrations inside web workers, they may not function as expected. But non-default integrations that are enabled outside of a worker’s scope won’t be affected and will function as expected. This includes Session Replay.
Note, that if you use non-default integrations inside web workers, they may not function as expected.
However, non-default integrations that are enabled on the main thread SDK, won't be affected and will work as expected.
This includes Session Replay.

## Source Maps

To ensure that errors from web workers are properly mapped to their original source code, you need to provide source maps to Sentry.
You likely already provide source maps to Sentry for your main application code, but you might need to make adjustments for your worker.

Importantly, ensure that your bundler also **emits source maps** for the worker bundle(s).

### Source Maps
### Vite
If you use Vite to build your worker, note that the worker build does not take the same plugin as the main code build.
Therefore, you need to add Sentry's Vite plugin to the worker build, in addition to the top-level `plugins` array:

Sentry's source maps integration is supported inside Web Workers, if provided. Learn more about providing your [source maps](/platforms/javascript/sourcemaps/) to Sentry.
```javascript {filename:vite.config.mjs}{1-4,8-9,13,16-17}
const sentryPlugin = sentryVitePlugin({
org: "sentry-sdks",
project: "javascript",
});

export default defineConfig({
build: {
// This enables source maps for main and worker bundles
sourcemap: "hidden",
},

// Vite plugin for main bundle
plugins: [sentryPlugin],

worker: {
// Vite plugin for worker bundle
plugins: () => [...sentryPlugin],
},
});
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
title: WebWorker
description: "Adds source code from inline JavaScript of the current page's HTML."
notSupported:
- javascript.cordova
- javascript.node
- javascript.aws-lambda
- javascript.azure-functions
- javascript.connect
- javascript.express
- javascript.fastify
- javascript.gcp-functions
- javascript.hapi
- javascript.hono
- javascript.koa
- javascript.nestjs
- javascript.deno
- javascript.cloudflare
- javascript.bun
---

_Import name: `Sentry.webWorkerIntegration`_

This integration, together with `Sentry.registerWorker()`, establishes communication between the browser's main thread and one or multiple [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API)s.
It listens to worker messages from the passed workers and forwards them to the main thread.

Read our <PlatformLink to="/best-practices/web-workers/">Web Worker Guide</PlatformLink> for more information.

<Expandable title="What does this integration do?">

This integration listens to a message, sent from the worker when it calls `Sentry.registerWorker({ self })`.
The purpose is to sync source map information (debugIds) between the main thread and the worker so that worker
errors caught by the main thread SDK are properly mapped to the worker's source code.

</Expandable>


## Options

### `worker`

_Type: `Worker | Array<Worker>`_

The web worker(s) to listen to. Every worker must call `Sentry.registerWorker({ self })` to register itself with the SDK.

## Methods

### `addWorker(worker: Worker)`

Adds a worker to the integration, after it was initialized.
This is useful if you have workers that are initialized at later point in your application's lifecycle.
Note that every worker must call `Sentry.registerWorker({ self })` to register itself with the SDK.
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@
| [`statsigIntegration`](./statsig) | | | | | ✓ |
| [`supabaseIntegration`](./supabase) | | ✓ | ✓ | | |
| [`unleashIntegration`](./unleash) | | | | | ✓ |
| [`webWorkerIntegration`](./webworker) | | ✓ | | | |