From 95c67329e487bae97cdf370daaca0bc218a004d0 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Thu, 18 Jun 2026 12:53:10 +0200 Subject: [PATCH] . --- .../sveltekit-3/tests/errors.server.test.ts | 7 +-- packages/sveltekit/src/vite/autoInstrument.ts | 8 +++- .../test/vite/autoInstrument.test.ts | 45 +++++++++++++++++++ 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-3/tests/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-3/tests/errors.server.test.ts index ee17fde7c048..d660cb6198d1 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-3/tests/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-3/tests/errors.server.test.ts @@ -2,12 +2,7 @@ import { expect, test } from '@playwright/test'; import { waitForError } from '@sentry-internal/test-utils'; test.describe('server-side errors', () => { - // FIXME(sveltekit-3): the universal load function's frame is reported as `load$1` (not `load`) - // because the SDK still wraps universal `+page.ts` load in the server build. Unlike server-only - // load, this isn't suppressed by native-tracing detection: the wrapper is skipped via - // `config.build.ssr`, which is unreliable under Vite 8's Environment API. Unskip once the SDK - // detects the server environment via the Vite Environment API. - test.skip('captures universal load error', async ({ page }) => { + test('captures universal load error', async ({ page }) => { const errorEventPromise = waitForError('sveltekit-3', errorEvent => { return errorEvent?.exception?.values?.[0]?.value === 'Universal Load Error (server)'; }); diff --git a/packages/sveltekit/src/vite/autoInstrument.ts b/packages/sveltekit/src/vite/autoInstrument.ts index a142d74f01cc..6b2f50928ee3 100644 --- a/packages/sveltekit/src/vite/autoInstrument.ts +++ b/packages/sveltekit/src/vite/autoInstrument.ts @@ -75,7 +75,13 @@ export function makeAutoInstrumentationPlugin(options: AutoInstrumentPluginOptio }, async load(id) { - if (onlyInstrumentClient && isServerBuild) { + // On Vite 6+ `config.build.ssr` captured in `configResolved` no longer reliably reflects the per-environment build. + // Prefer the environment of the current build (`this.environment.name === 'ssr'`) and fall back to + // `isServerBuild` for older Vite versions that don't expose environments. + const environmentName = (this as { environment?: { name?: string } }).environment?.name; + const isServerEnvironment = environmentName != null ? environmentName === 'ssr' : !!isServerBuild; + + if (onlyInstrumentClient && isServerEnvironment) { return null; } diff --git a/packages/sveltekit/test/vite/autoInstrument.test.ts b/packages/sveltekit/test/vite/autoInstrument.test.ts index 54f6ccb6c425..4a3d3cce4476 100644 --- a/packages/sveltekit/test/vite/autoInstrument.test.ts +++ b/packages/sveltekit/test/vite/autoInstrument.test.ts @@ -280,6 +280,51 @@ describe('makeAutoInstrumentationPlugin()', () => { ); }); }); + + describe('when the server build is detected via the Vite Environment API', () => { + // On Vite 6+ `config.build.ssr` no longer reliably reflects the per-environment + // build, so the plugin relies on the current environment (`this.environment.name`). When + // `onlyInstrumentClient` is `true`, universal load must not be wrapped in the `ssr` environment + // (but should still be wrapped in `client`), even when `config.build.ssr`/`configResolved` + // didn't flag a server build. + it.each(['path/to/+page.ts', 'path/to/+layout.js', 'path/to/+page.server.ts'])( + "doesn't wrap %s in the `ssr` environment", + async (path: string) => { + const plugin = makeAutoInstrumentationPlugin({ + debug: false, + load: true, + serverLoad: true, + onlyInstrumentClient: true, + }); + + // `configResolved` is intentionally not called - `isServerBuild` stays `undefined` + // @ts-expect-error this exists and is callable; bind `this.environment` like Vite does + const loadResult = await plugin.load.call({ environment: { name: 'ssr' } }, path); + + expect(loadResult).toEqual(null); + }, + ); + + it('still wraps universal load in the `client` environment', async () => { + const plugin = makeAutoInstrumentationPlugin({ + debug: false, + load: true, + serverLoad: true, + onlyInstrumentClient: true, + }); + + const path = 'path/to/+page.ts'; + // @ts-expect-error this exists and is callable; bind `this.environment` like Vite does + const loadResult = await plugin.load.call({ environment: { name: 'client' } }, path); + + expect(loadResult).toBe( + 'import { wrapLoadWithSentry } from "@sentry/sveltekit";' + + `import * as userModule from "${path}?sentry-auto-wrap";` + + 'export const load = userModule.load ? wrapLoadWithSentry(userModule.load) : undefined;' + + `export * from "${path}?sentry-auto-wrap";`, + ); + }); + }); }); describe('canWrapLoad', () => {