diff --git a/packages/vite/src/node/ssr/ssrModuleLoader.ts b/packages/vite/src/node/ssr/ssrModuleLoader.ts index 466039d82b2ae2..cd234876a748e6 100644 --- a/packages/vite/src/node/ssr/ssrModuleLoader.ts +++ b/packages/vite/src/node/ssr/ssrModuleLoader.ts @@ -28,6 +28,7 @@ type SSRModule = Record const pendingModules = new Map>() const pendingImports = new Map() +const importErrors = new WeakMap() export async function ssrLoadModule( url: string, @@ -131,32 +132,39 @@ async function instantiateModule( const pendingDeps: string[] = [] const ssrImport = async (dep: string) => { - if (dep[0] !== '.' && dep[0] !== '/') { - return nodeImport(dep, mod.file!, resolveOptions) - } - // convert to rollup URL because `pendingImports`, `moduleGraph.urlToModuleMap` requires that - dep = unwrapId(dep) - if (!isCircular(dep) && !pendingImports.get(dep)?.some(isCircular)) { - pendingDeps.push(dep) - if (pendingDeps.length === 1) { - pendingImports.set(url, pendingDeps) + try { + if (dep[0] !== '.' && dep[0] !== '/') { + return await nodeImport(dep, mod.file!, resolveOptions) } - const mod = await ssrLoadModule( - dep, - server, - context, - urlStack, - fixStacktrace, - ) - if (pendingDeps.length === 1) { - pendingImports.delete(url) - } else { - pendingDeps.splice(pendingDeps.indexOf(dep), 1) + // convert to rollup URL because `pendingImports`, `moduleGraph.urlToModuleMap` requires that + dep = unwrapId(dep) + if (!isCircular(dep) && !pendingImports.get(dep)?.some(isCircular)) { + pendingDeps.push(dep) + if (pendingDeps.length === 1) { + pendingImports.set(url, pendingDeps) + } + const mod = await ssrLoadModule( + dep, + server, + context, + urlStack, + fixStacktrace, + ) + if (pendingDeps.length === 1) { + pendingImports.delete(url) + } else { + pendingDeps.splice(pendingDeps.indexOf(dep), 1) + } + // return local module to avoid race condition #5470 + return mod } - // return local module to avoid race condition #5470 - return mod + return moduleGraph.urlToModuleMap.get(dep)?.ssrModule + } catch (err) { + // tell external error handler which mod was imported with error + importErrors.set(err, { importee: dep }) + + throw err } - return moduleGraph.urlToModuleMap.get(dep)?.ssrModule } const ssrDynamicImport = (dep: string) => { @@ -204,6 +212,7 @@ async function instantiateModule( ) } catch (e) { mod.ssrError = e + const errorData = importErrors.get(e) if (e.stack && fixStacktrace) { ssrFixStacktrace(e, moduleGraph) @@ -212,7 +221,10 @@ async function instantiateModule( server.config.logger.error( colors.red( `Error when evaluating SSR module ${url}:` + - (e.importee ? ` failed to import "${e.importee}"\n` : '\n'), + (errorData?.importee + ? ` failed to import "${errorData.importee}"` + : '') + + `\n|- ${e.stack}\n`, ), { timestamp: true, @@ -221,7 +233,6 @@ async function instantiateModule( }, ) - delete e.importee throw e } @@ -262,15 +273,8 @@ async function nodeImport( } } - try { - const mod = await dynamicImport(url) - return proxyESM(mod) - } catch (err) { - // tell external error handler which mod was imported with error - err.importee = id - - throw err - } + const mod = await dynamicImport(url) + return proxyESM(mod) } // rollup-style default import interop for cjs