diff --git a/packages/vite/src/node/server/index.ts b/packages/vite/src/node/server/index.ts index 238725da4b4458..d25ab50aa749e5 100644 --- a/packages/vite/src/node/server/index.ts +++ b/packages/vite/src/node/server/index.ts @@ -31,10 +31,7 @@ import { } from '../utils' import { ssrLoadModule } from '../ssr/ssrModuleLoader' import { cjsSsrResolveExternals } from '../ssr/ssrExternal' -import { - rebindErrorStacktrace, - ssrRewriteStacktrace, -} from '../ssr/ssrStacktrace' +import { ssrFixStacktrace, ssrRewriteStacktrace } from '../ssr/ssrStacktrace' import { ssrTransform } from '../ssr/ssrTransform' import { getDepsOptimizer, @@ -388,10 +385,7 @@ export async function createServer( ) }, ssrFixStacktrace(e) { - if (e.stack) { - const stacktrace = ssrRewriteStacktrace(e.stack, moduleGraph) - rebindErrorStacktrace(e, stacktrace) - } + ssrFixStacktrace(e, moduleGraph) }, ssrRewriteStacktrace(stack: string) { return ssrRewriteStacktrace(stack, moduleGraph) diff --git a/packages/vite/src/node/ssr/__tests__/fixtures/modules/has-error.js b/packages/vite/src/node/ssr/__tests__/fixtures/modules/has-error.js new file mode 100644 index 00000000000000..ef6d5d4df85621 --- /dev/null +++ b/packages/vite/src/node/ssr/__tests__/fixtures/modules/has-error.js @@ -0,0 +1 @@ +throw new Error() diff --git a/packages/vite/src/node/ssr/__tests__/ssrLoadModule.spec.ts b/packages/vite/src/node/ssr/__tests__/ssrLoadModule.spec.ts index a21b0673e1f36d..8b81372a2697dd 100644 --- a/packages/vite/src/node/ssr/__tests__/ssrLoadModule.spec.ts +++ b/packages/vite/src/node/ssr/__tests__/ssrLoadModule.spec.ts @@ -21,3 +21,23 @@ test('ssrLoad', async () => { ) } }) + +test('error has same instance', async () => { + expect.assertions(3) + const s = Symbol() + + const server = await createDevServer() + try { + await server.ssrLoadModule('/fixtures/modules/has-error.js') + } catch (e) { + expect(e[s]).toBeUndefined() + e[s] = true + expect(e[s]).toBe(true) + } + + try { + await server.ssrLoadModule('/fixtures/modules/has-error.js') + } catch (e) { + expect(e[s]).toBe(true) + } +}) diff --git a/packages/vite/src/node/ssr/__tests__/ssrStacktrace.spec.ts b/packages/vite/src/node/ssr/__tests__/ssrStacktrace.spec.ts new file mode 100644 index 00000000000000..c7f89822171794 --- /dev/null +++ b/packages/vite/src/node/ssr/__tests__/ssrStacktrace.spec.ts @@ -0,0 +1,22 @@ +import { fileURLToPath } from 'node:url' +import { test } from 'vitest' +import { createServer } from '../../server' + +const root = fileURLToPath(new URL('./', import.meta.url)) + +async function createDevServer() { + const server = await createServer({ configFile: false, root }) + server.pluginContainer.buildStart({}) + return server +} + +test('call rewriteStacktrace twice', async () => { + const server = await createDevServer() + for (let i = 0; i < 2; i++) { + try { + await server.ssrLoadModule('/fixtures/modules/has-error.js') + } catch (e) { + server.ssrFixStacktrace(e) + } + } +}) diff --git a/packages/vite/src/node/ssr/ssrModuleLoader.ts b/packages/vite/src/node/ssr/ssrModuleLoader.ts index 9c9916ca616564..8f1b377ab70060 100644 --- a/packages/vite/src/node/ssr/ssrModuleLoader.ts +++ b/packages/vite/src/node/ssr/ssrModuleLoader.ts @@ -17,7 +17,7 @@ import { ssrImportMetaKey, ssrModuleExportsKey, } from './ssrTransform' -import { rebindErrorStacktrace, ssrRewriteStacktrace } from './ssrStacktrace' +import { ssrFixStacktrace } from './ssrStacktrace' interface SSRContext { global: typeof globalThis @@ -203,10 +203,9 @@ async function instantiateModule( } catch (e) { mod.ssrError = e if (e.stack && fixStacktrace) { - const stacktrace = ssrRewriteStacktrace(e.stack, moduleGraph) - rebindErrorStacktrace(e, stacktrace) + ssrFixStacktrace(e, moduleGraph) server.config.logger.error( - `Error when evaluating SSR module ${url}:\n${stacktrace}`, + `Error when evaluating SSR module ${url}:\n${e.stack}`, { timestamp: true, clear: server.config.clearScreen, diff --git a/packages/vite/src/node/ssr/ssrStacktrace.ts b/packages/vite/src/node/ssr/ssrStacktrace.ts index cad1bd17e0422e..53e897d096b9cd 100644 --- a/packages/vite/src/node/ssr/ssrStacktrace.ts +++ b/packages/vite/src/node/ssr/ssrStacktrace.ts @@ -71,3 +71,16 @@ export function rebindErrorStacktrace(e: Error, stacktrace: string): void { e.stack = stacktrace } } + +const rewroteStacktraces = new WeakSet() + +export function ssrFixStacktrace(e: Error, moduleGraph: ModuleGraph): void { + if (!e.stack) return + // stacktrace shouldn't be rewritten more than once + if (rewroteStacktraces.has(e)) return + + const stacktrace = ssrRewriteStacktrace(e.stack, moduleGraph) + rebindErrorStacktrace(e, stacktrace) + + rewroteStacktraces.add(e) +}