From bd8900d0c8eb798a3d5b63bf163aef9c87c10061 Mon Sep 17 00:00:00 2001 From: neverland Date: Tue, 30 Sep 2025 14:50:07 +0800 Subject: [PATCH 1/2] feat(core): improve module trace formatting in error messages --- .../diagnostic/import-traces/index.test.ts | 25 ++++++++++ .../diagnostic/import-traces/src/child1.js | 1 + .../diagnostic/import-traces/src/child2.js | 1 + .../diagnostic/import-traces/src/child3.js | 1 + .../diagnostic/import-traces/src/index.js | 1 + .../index.test.ts | 0 .../src/index.js | 0 .../index.test.ts | 0 .../src/index.js | 0 packages/core/src/helpers/format.ts | 46 +++++++++++++------ 10 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 e2e/cases/diagnostic/import-traces/index.test.ts create mode 100644 e2e/cases/diagnostic/import-traces/src/child1.js create mode 100644 e2e/cases/diagnostic/import-traces/src/child2.js create mode 100644 e2e/cases/diagnostic/import-traces/src/child3.js create mode 100644 e2e/cases/diagnostic/import-traces/src/index.js rename e2e/cases/{polyfill => diagnostic}/node-polyfill-tip-with-protocol/index.test.ts (100%) rename e2e/cases/{polyfill => diagnostic}/node-polyfill-tip-with-protocol/src/index.js (100%) rename e2e/cases/{polyfill => diagnostic}/node-polyfill-tip-without-protocol/index.test.ts (100%) rename e2e/cases/{polyfill => diagnostic}/node-polyfill-tip-without-protocol/src/index.js (100%) 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 --'; From 525009d8625ae71c76a2d5ec4781d6807bdd3416 Mon Sep 17 00:00:00 2001 From: neverland Date: Tue, 30 Sep 2025 15:04:16 +0800 Subject: [PATCH 2/2] fix --- e2e/cases/config/stats-module-trace/index.test.ts | 10 ---------- e2e/cases/config/stats-module-trace/src/index.tsx | 1 - e2e/cases/config/stats-module-trace/src/test.tsx | 1 - 3 files changed, 12 deletions(-) delete mode 100644 e2e/cases/config/stats-module-trace/index.test.ts delete mode 100644 e2e/cases/config/stats-module-trace/src/index.tsx delete mode 100644 e2e/cases/config/stats-module-trace/src/test.tsx 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';