diff --git a/docs/platforms/javascript/common/best-practices/web-workers.mdx b/docs/platforms/javascript/common/best-practices/web-workers.mdx index 65e3ff870948c..989df30639a9c 100644 --- a/docs/platforms/javascript/common/best-practices/web-workers.mdx +++ b/docs/platforms/javascript/common/best-practices/web-workers.mdx @@ -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 @@ -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({ @@ -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) => { + // ... +} ``` - + -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. -#### 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 + + +- 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. + + + +## 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({ @@ -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). + + + +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). + + + ### 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], + }, +}); +``` \ No newline at end of file diff --git a/docs/platforms/javascript/common/configuration/integrations/webworker.mdx b/docs/platforms/javascript/common/configuration/integrations/webworker.mdx new file mode 100644 index 0000000000000..01b98e2e00df8 --- /dev/null +++ b/docs/platforms/javascript/common/configuration/integrations/webworker.mdx @@ -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 Web Worker Guide for more information. + + + +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. + + + + +## Options + +### `worker` + +_Type: `Worker | Array`_ + +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. diff --git a/platform-includes/configuration/integrations/javascript.mdx b/platform-includes/configuration/integrations/javascript.mdx index 02f7f9004fa0a..5141099d4ed84 100644 --- a/platform-includes/configuration/integrations/javascript.mdx +++ b/platform-includes/configuration/integrations/javascript.mdx @@ -29,3 +29,4 @@ | [`statsigIntegration`](./statsig) | | | | | ✓ | | [`supabaseIntegration`](./supabase) | | ✓ | ✓ | | | | [`unleashIntegration`](./unleash) | | | | | ✓ | +| [`webWorkerIntegration`](./webworker) | | ✓ | | | |