diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-3/src/env.ts b/dev-packages/e2e-tests/test-applications/sveltekit-3/src/env.ts index 7ef441db0a82..ce7e354ed8b6 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-3/src/env.ts +++ b/dev-packages/e2e-tests/test-applications/sveltekit-3/src/env.ts @@ -1,4 +1,4 @@ -import { defineEnvVars } from '@sveltejs/kit/hooks'; +import { defineEnvVars } from '@sveltejs/kit/env'; // SvelteKit 3 makes "explicit environment variables" the default and removes the // legacy `$env/*` virtual modules. Declared vars are imported from `$app/env/private` 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 d660cb6198d1..447f4fa07890 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 @@ -70,7 +70,7 @@ test.describe('server-side errors', () => { expect(errorEventFrames?.[errorEventFrames?.length - 1]).toEqual( expect.objectContaining({ - filename: expect.stringMatching(/app:\/\/\/_server.ts-.+.js/), + filename: 'app:///src/routes/server-route-error/+server.ts', function: 'GET', in_app: true, }), diff --git a/packages/sveltekit/src/server-common/integrations/rewriteFramesIntegration.ts b/packages/sveltekit/src/server-common/integrations/rewriteFramesIntegration.ts index 67a72bcd6ed2..f9f6873d2933 100644 --- a/packages/sveltekit/src/server-common/integrations/rewriteFramesIntegration.ts +++ b/packages/sveltekit/src/server-common/integrations/rewriteFramesIntegration.ts @@ -68,6 +68,13 @@ export function rewriteFramesIteratee(frame: StackFrame): StackFrame { strippedFilename = basename(filename); } frame.filename = `${prefix}${strippedFilename}`; + } else if (isAppRelativeSourceFrame(frame.filename)) { + // SvelteKit 3 (Vite/Rolldown) source-maps server frames to relative project paths such as + // `src/routes/+page.ts` instead of the previous bundled absolute chunk paths. These skip the + // branch above, so the default parser marks them as `in_app: false` (relative paths look like + // Node internals). Prefix them like the absolute frames and flag them as app code. + frame.filename = `${prefix}${frame.filename.replace(/^\.\//, '')}`; + frame.in_app = true; } delete frame.module; @@ -80,3 +87,12 @@ export function rewriteFramesIteratee(frame: StackFrame): StackFrame { return frame; } + +/** + * Whether a (non-absolute) frame filename is an app-relative source path like `src/routes/+page.ts`, + * as opposed to a dependency or a Node built-in. Excludes `node_modules` and any scheme/drive prefix + * (e.g. `node:`, `data:`, `C:/`). + */ +function isAppRelativeSourceFrame(filename: string): boolean { + return !filename.includes('node_modules/') && !/^[a-zA-Z][a-zA-Z0-9.+-]*:/.test(filename); +} diff --git a/packages/sveltekit/test/server-common/integrations/rewriteFramesIntegration.test.ts b/packages/sveltekit/test/server-common/integrations/rewriteFramesIntegration.test.ts index 836152a81eb0..7ea92b899524 100644 --- a/packages/sveltekit/test/server-common/integrations/rewriteFramesIntegration.test.ts +++ b/packages/sveltekit/test/server-common/integrations/rewriteFramesIntegration.test.ts @@ -52,6 +52,45 @@ describe('rewriteFramesIteratee', () => { expect(result).toStrictEqual(originalResult); }); + it.each([ + ['src/routes/universal-load-error/+page.ts', 'app:///src/routes/universal-load-error/+page.ts'], + ['./src/routes/server-load-error/+page.server.ts', 'app:///src/routes/server-load-error/+page.server.ts'], + ['src/hooks.server.ts', 'app:///src/hooks.server.ts'], + ])('rewrites and flags SvelteKit 3 app-relative source frames as in_app (%s)', (frameFilename, modifiedFilename) => { + const frame: StackFrame = { + filename: frameFilename, + lineno: 2, + colno: 9, + function: 'load', + }; + + const result = rewriteFramesIteratee({ ...frame }); + + expect(result).toStrictEqual({ + filename: modifiedFilename, + lineno: 2, + colno: 9, + function: 'load', + in_app: true, + }); + }); + + it.each([['node_modules/@sveltejs/kit/src/runtime/server/index.js'], ['node:internal/process/task_queues']])( + 'does not rewrite or flag dependency/internal relative frames (%s)', + frameFilename => { + const frame: StackFrame = { + filename: frameFilename, + lineno: 1, + colno: 1, + }; + + const result = rewriteFramesIteratee({ ...frame }); + + expect(result.filename).toBe(frameFilename); + expect(result.in_app).toBeUndefined(); + }, + ); + it.each([ ['adapter-node', 'build', '/absolute/path/to/build/server/chunks/3-ab34d22f.js', 'app:///chunks/3-ab34d22f.js'], [