diff --git a/e2e/cases/config/stats-module-trace/index.test.ts b/e2e/cases/config/stats-module-trace/index.test.ts deleted file mode 100644 index f224aae3fa..0000000000 --- a/e2e/cases/config/stats-module-trace/index.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { expect, test } from '@e2e/helper'; - -test('should log error module trace', async ({ build }) => { - const rsbuild = await build({ - catchBuildError: true, - }); - - expect(rsbuild.buildError).toBeTruthy(); - await rsbuild.expectLog('@ ./src/index.tsx'); -}); diff --git a/e2e/cases/config/stats-module-trace/src/index.tsx b/e2e/cases/config/stats-module-trace/src/index.tsx deleted file mode 100644 index 41e183492d..0000000000 --- a/e2e/cases/config/stats-module-trace/src/index.tsx +++ /dev/null @@ -1 +0,0 @@ -import './test'; diff --git a/e2e/cases/config/stats-module-trace/src/test.tsx b/e2e/cases/config/stats-module-trace/src/test.tsx deleted file mode 100644 index 05147212a4..0000000000 --- a/e2e/cases/config/stats-module-trace/src/test.tsx +++ /dev/null @@ -1 +0,0 @@ -import './test1'; diff --git a/e2e/cases/diagnostic/import-traces/index.test.ts b/e2e/cases/diagnostic/import-traces/index.test.ts new file mode 100644 index 0000000000..41c022d369 --- /dev/null +++ b/e2e/cases/diagnostic/import-traces/index.test.ts @@ -0,0 +1,25 @@ +import { expect, test } from '@e2e/helper'; + +const EXPECTED_LOG = `Import traces (entry → error): + ./src/index.js + ./src/child1.js + ./src/child2.js + ./src/child3.js ×`; + +test('should print import traces if module build failed in dev', async ({ + dev, +}) => { + const rsbuild = await dev(); + await rsbuild.expectLog(EXPECTED_LOG); +}); + +test('should print import traces if module build failed in build', async ({ + build, +}) => { + const rsbuild = await build({ + catchBuildError: true, + }); + + expect(rsbuild.buildError).toBeTruthy(); + await rsbuild.expectLog(EXPECTED_LOG); +}); diff --git a/e2e/cases/diagnostic/import-traces/src/child1.js b/e2e/cases/diagnostic/import-traces/src/child1.js new file mode 100644 index 0000000000..60dfc60277 --- /dev/null +++ b/e2e/cases/diagnostic/import-traces/src/child1.js @@ -0,0 +1 @@ +import './child2'; diff --git a/e2e/cases/diagnostic/import-traces/src/child2.js b/e2e/cases/diagnostic/import-traces/src/child2.js new file mode 100644 index 0000000000..f73329cc38 --- /dev/null +++ b/e2e/cases/diagnostic/import-traces/src/child2.js @@ -0,0 +1 @@ +import './child3'; diff --git a/e2e/cases/diagnostic/import-traces/src/child3.js b/e2e/cases/diagnostic/import-traces/src/child3.js new file mode 100644 index 0000000000..aa36acaa32 --- /dev/null +++ b/e2e/cases/diagnostic/import-traces/src/child3.js @@ -0,0 +1 @@ +import './child4'; diff --git a/e2e/cases/diagnostic/import-traces/src/index.js b/e2e/cases/diagnostic/import-traces/src/index.js new file mode 100644 index 0000000000..74d7af1f4e --- /dev/null +++ b/e2e/cases/diagnostic/import-traces/src/index.js @@ -0,0 +1 @@ +import './child1'; diff --git a/e2e/cases/polyfill/node-polyfill-tip-with-protocol/index.test.ts b/e2e/cases/diagnostic/node-polyfill-tip-with-protocol/index.test.ts similarity index 100% rename from e2e/cases/polyfill/node-polyfill-tip-with-protocol/index.test.ts rename to e2e/cases/diagnostic/node-polyfill-tip-with-protocol/index.test.ts diff --git a/e2e/cases/polyfill/node-polyfill-tip-with-protocol/src/index.js b/e2e/cases/diagnostic/node-polyfill-tip-with-protocol/src/index.js similarity index 100% rename from e2e/cases/polyfill/node-polyfill-tip-with-protocol/src/index.js rename to e2e/cases/diagnostic/node-polyfill-tip-with-protocol/src/index.js diff --git a/e2e/cases/polyfill/node-polyfill-tip-without-protocol/index.test.ts b/e2e/cases/diagnostic/node-polyfill-tip-without-protocol/index.test.ts similarity index 100% rename from e2e/cases/polyfill/node-polyfill-tip-without-protocol/index.test.ts rename to e2e/cases/diagnostic/node-polyfill-tip-without-protocol/index.test.ts diff --git a/e2e/cases/polyfill/node-polyfill-tip-without-protocol/src/index.js b/e2e/cases/diagnostic/node-polyfill-tip-without-protocol/src/index.js similarity index 100% rename from e2e/cases/polyfill/node-polyfill-tip-without-protocol/src/index.js rename to e2e/cases/diagnostic/node-polyfill-tip-without-protocol/src/index.js diff --git a/packages/core/src/helpers/format.ts b/packages/core/src/helpers/format.ts index 38d7b6bb27..cc4652801a 100644 --- a/packages/core/src/helpers/format.ts +++ b/packages/core/src/helpers/format.ts @@ -19,7 +19,7 @@ function resolveFileName(stats: StatsError) { stats.moduleName; if (file) { - return formatFileName(file); + return file; } // `moduleIdentifier` is the absolute path with inline loaders @@ -30,7 +30,7 @@ function resolveFileName(stats: StatsError) { if (matched) { const fileName = matched.pop(); if (fileName) { - return formatFileName(fileName); + return fileName; } } } @@ -38,18 +38,36 @@ function resolveFileName(stats: StatsError) { return ''; } -function resolveModuleTrace(stats: StatsError) { - let traceStr = ''; - if (stats.moduleTrace) { - for (const trace of stats.moduleTrace) { - if (trace.originName) { - // TODO: missing moduleTrace.dependencies[].loc in rspack - traceStr += `\n @ ${trace.originName}`; - } - } +/** + * Format the module trace, the output be like: + * Import traces (entry → error): + * ./src/index.tsx + * ./src/App.tsx + * ./src/Foo.tsx × + */ +function formatModuleTrace(stats: StatsError, errorFile: string) { + if (!stats.moduleTrace) { + return; + } + + const moduleNames = stats.moduleTrace + .map((trace) => trace.originName) + .filter(Boolean) as string[]; + + if (!moduleNames.length) { + return; } - return traceStr; + if (errorFile) { + moduleNames.unshift(`${errorFile} ${color.bold(color.red('×'))}`); + } + + const rawTrace = moduleNames + .reverse() + .map((item) => `\n ${item}`) + .join(''); + + return color.dim(`Import traces (entry → error):${rawTrace}`); } function hintUnknownFiles(message: string): string { @@ -202,9 +220,9 @@ export function formatStatsError(stats: StatsError, verbose?: boolean): string { const details = verbose && stats.details ? `\nDetails: ${stats.details}\n` : ''; const stack = verbose && stats.stack ? `\n${stats.stack}` : ''; - const moduleTrace = resolveModuleTrace(stats); + const moduleTrace = formatModuleTrace(stats, fileName) ?? ''; - message = `${fileName}${mainMessage}${details}${stack}${moduleTrace}`; + message = `${formatFileName(fileName)}${mainMessage}${details}${stack}${moduleTrace}`; // Remove inner error message const innerError = '-- inner error --';