Skip to content

Commit c1fb66b

Browse files
authored
refactor(stats): improve stats error and warning handling (#6297)
1 parent 0054710 commit c1fb66b

File tree

7 files changed

+107
-69
lines changed

7 files changed

+107
-69
lines changed

packages/compat/webpack/src/createCompiler.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { logger, type Rspack } from '@rsbuild/core';
1+
import { logger, type RsbuildStats, type Rspack } from '@rsbuild/core';
22
import WebpackMultiStats from 'webpack/lib/MultiStats.js';
33
import { type InitConfigsOptions, initConfigs } from './initConfigs.js';
44

@@ -35,20 +35,21 @@ export async function createCompiler(options: InitConfigsOptions) {
3535
context.buildState.hasErrors = false;
3636
});
3737

38-
compiler.hooks.done.tap(HOOK_NAME, (stats) => {
39-
const hasErrors = stats.hasErrors();
40-
context.buildState.hasErrors = hasErrors;
41-
context.buildState.status = 'done';
42-
38+
compiler.hooks.done.tap(HOOK_NAME, (statsInstance) => {
4339
const statsOptions = helpers.getStatsOptions(compiler);
44-
const statsJson = stats.toJson({
40+
const stats = statsInstance.toJson({
4541
moduleTrace: true,
4642
children: true,
47-
preset: 'errors-warnings',
43+
errors: true,
44+
warnings: true,
4845
...statsOptions,
49-
});
46+
}) as RsbuildStats;
47+
48+
const hasErrors = helpers.getStatsErrors(stats).length > 0;
49+
context.buildState.hasErrors = hasErrors;
50+
context.buildState.status = 'done';
5051

51-
const { message, level } = helpers.formatStats(statsJson, hasErrors);
52+
const { message, level } = helpers.formatStats(stats, hasErrors);
5253

5354
if (level === 'error') {
5455
logger.error(message);

packages/core/src/helpers/stats.ts

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import type { StatsCompilation } from '@rspack/core';
21
import color from '../../compiled/picocolors/index.js';
32
import { logger } from '../logger';
4-
import type { Rspack } from '../types';
3+
import type { RsbuildStats, Rspack } from '../types';
54
import { isMultiCompiler } from './';
65
import { formatStatsError } from './format';
76

@@ -19,19 +18,46 @@ function formatErrorMessage(errors: string[]) {
1918
return `${title}\n${text}`;
2019
}
2120

22-
export const getAllStatsErrors = (
23-
statsData: StatsCompilation,
24-
): Rspack.StatsError[] | undefined => {
25-
// stats error + childCompiler error
26-
// only append child errors when stats error does not exist, because some errors will exist in both stats and childCompiler
27-
if (statsData.errorsCount && statsData.errors?.length === 0) {
28-
return statsData.children?.reduce<Rspack.StatsError[]>(
29-
(errors, curr) => errors.concat(curr.errors || []),
21+
/**
22+
* If stats has errors, return stats errors directly
23+
* If stats has no errors, return child errors, as some errors exist in both
24+
* stats and childCompiler
25+
*/
26+
export const getStatsErrors = ({
27+
errors,
28+
children,
29+
}: RsbuildStats): Rspack.StatsError[] => {
30+
if (errors !== undefined && errors.length > 0) {
31+
return errors;
32+
}
33+
34+
if (children) {
35+
return children.reduce<Rspack.StatsError[]>(
36+
(errors, ret) => (ret.errors ? errors.concat(ret.errors) : errors),
37+
[],
38+
);
39+
}
40+
41+
return [];
42+
};
43+
44+
export const getStatsWarnings = ({
45+
warnings,
46+
children,
47+
}: RsbuildStats): Rspack.StatsError[] => {
48+
if (warnings !== undefined && warnings.length > 0) {
49+
return warnings;
50+
}
51+
52+
if (children) {
53+
return children.reduce<Rspack.StatsError[]>(
54+
(warnings, ret) =>
55+
ret.warnings ? warnings.concat(ret.warnings) : warnings,
3056
[],
3157
);
3258
}
3359

34-
return statsData.errors;
60+
return [];
3561
};
3662

3763
export const getAssetsFromStats = (
@@ -51,19 +77,6 @@ export const getAssetsFromStats = (
5177
return statsJson.assets || [];
5278
};
5379

54-
export const getAllStatsWarnings = (
55-
statsData: StatsCompilation,
56-
): Rspack.StatsError[] | undefined => {
57-
if (statsData.warningsCount && statsData.warnings?.length === 0) {
58-
return statsData.children?.reduce<Rspack.StatsError[]>(
59-
(warnings, curr) => warnings.concat(curr.warnings || []),
60-
[],
61-
);
62-
}
63-
64-
return statsData.warnings;
65-
};
66-
6780
export function getStatsOptions(
6881
compiler: Rspack.Compiler | Rspack.MultiCompiler,
6982
): Rspack.StatsOptions {
@@ -88,7 +101,7 @@ export function getStatsOptions(
88101
}
89102

90103
export function formatStats(
91-
statsData: Rspack.StatsCompilation,
104+
stats: RsbuildStats,
92105
hasErrors: boolean,
93106
): {
94107
message?: string;
@@ -98,15 +111,15 @@ export function formatStats(
98111
const verbose = logger.level === 'verbose';
99112

100113
if (hasErrors) {
101-
const statsErrors = getAllStatsErrors(statsData) ?? [];
114+
const statsErrors = getStatsErrors(stats);
102115
const errors = statsErrors.map((item) => formatStatsError(item, verbose));
103116
return {
104117
message: formatErrorMessage(errors),
105118
level: 'error',
106119
};
107120
}
108121

109-
const statsWarnings = getAllStatsWarnings(statsData) ?? [];
122+
const statsWarnings = getStatsWarnings(stats);
110123
const warnings = statsWarnings.map((item) => formatStatsError(item, verbose));
111124

112125
if (warnings.length) {

packages/core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ export type {
175175
RsbuildPlugins,
176176
RsbuildProvider,
177177
RsbuildProviderHelpers,
178+
RsbuildStats,
178179
RsbuildTarget,
179180
RspackChain,
180181
RspackRule,

packages/core/src/provider/createCompiler.ts

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { sep } from 'node:path';
2-
import type { StatsCompilation } from '@rspack/core';
32
import {
43
color,
54
formatStats,
5+
getStatsErrors,
66
getStatsOptions,
77
isSatisfyRspackVersion,
88
prettyTime,
@@ -11,7 +11,12 @@ import {
1111
import { registerDevHook } from '../hooks';
1212
import { logger } from '../logger';
1313
import { rspack } from '../rspack';
14-
import type { InternalContext, Rspack } from '../types';
14+
import type {
15+
InternalContext,
16+
RsbuildStats,
17+
RsbuildStatsItem,
18+
Rspack,
19+
} from '../types';
1520
import { type InitConfigsOptions, initConfigs } from './initConfigs';
1621

1722
// keep the last 3 parts of the path to make logs clean
@@ -184,24 +189,25 @@ export async function createCompiler(options: InitConfigsOptions): Promise<{
184189

185190
compiler.hooks.done.tap(
186191
HOOK_NAME,
187-
(stats: Rspack.Stats | Rspack.MultiStats) => {
188-
const hasErrors = stats.hasErrors();
189-
context.buildState.hasErrors = hasErrors;
190-
context.buildState.status = 'done';
191-
192+
(statsInstance: Rspack.Stats | Rspack.MultiStats) => {
192193
const statsOptions = getStatsOptions(compiler);
193-
const statsJson = stats.toJson({
194+
const stats = statsInstance.toJson({
194195
children: true,
195196
moduleTrace: true,
196197
// get the compilation time
197198
timings: true,
198-
preset: 'errors-warnings',
199+
errors: true,
200+
warnings: true,
199201
...statsOptions,
200-
});
202+
}) as RsbuildStats;
203+
204+
const hasErrors = getStatsErrors(stats).length > 0;
205+
context.buildState.status = 'done';
206+
context.buildState.hasErrors = hasErrors;
201207

202-
const printTime = (c: StatsCompilation, index: number) => {
203-
if (c.time) {
204-
const time = prettyTime(c.time / 1000);
208+
const printTime = (statsItem: RsbuildStatsItem, index: number) => {
209+
if (statsItem.time) {
210+
const time = prettyTime(statsItem.time / 1000);
205211
const { name } = rspackConfigs[index];
206212

207213
// When using multi compiler, print name to distinguish different compilers
@@ -212,16 +218,16 @@ export async function createCompiler(options: InitConfigsOptions): Promise<{
212218

213219
if (!hasErrors) {
214220
// only print children compiler time when multi compiler
215-
if (isMultiCompiler && statsJson.children?.length) {
216-
statsJson.children.forEach((c, index) => {
221+
if (isMultiCompiler && stats.children?.length) {
222+
stats.children.forEach((c, index) => {
217223
printTime(c, index);
218224
});
219225
} else {
220-
printTime(statsJson, 0);
226+
printTime(stats, 0);
221227
}
222228
}
223229

224-
const { message, level } = formatStats(statsJson, hasErrors);
230+
const { message, level } = formatStats(stats, hasErrors);
225231

226232
if (level === 'error') {
227233
logger.error(message);

packages/core/src/provider/helpers.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
*/
44

55
export { modifyBundlerChain } from '../configChain';
6-
export { formatStats, getStatsOptions, prettyTime } from '../helpers';
6+
export {
7+
formatStats,
8+
getStatsErrors,
9+
getStatsOptions,
10+
prettyTime,
11+
} from '../helpers';
712
export { registerBuildHook, registerDevHook } from '../hooks';
813
export { inspectConfig } from '../inspectConfig';
914
export {

packages/core/src/server/socketServer.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import type { IncomingMessage } from 'node:http';
22
import type { Socket } from 'node:net';
33
import type Ws from '../../compiled/ws/index.js';
4-
import {
5-
getAllStatsErrors,
6-
getAllStatsWarnings,
7-
getStatsOptions,
8-
} from '../helpers';
4+
import { getStatsErrors, getStatsOptions, getStatsWarnings } from '../helpers';
95
import { formatStatsError } from '../helpers/format';
106
import { logger } from '../logger';
11-
import type { DevConfig, InternalContext, Rspack } from '../types';
7+
import type {
8+
DevConfig,
9+
InternalContext,
10+
RsbuildStats,
11+
Rspack,
12+
} from '../types';
1213
import { formatBrowserErrorLog } from './browserLogs';
1314
import { genOverlayHTML } from './overlay';
1415

@@ -338,9 +339,7 @@ export class SocketServer {
338339
all: false,
339340
hash: true,
340341
warnings: true,
341-
warningsCount: true,
342342
errors: true,
343-
errorsCount: true,
344343
errorDetails: false,
345344
entrypoints: true,
346345
children: true,
@@ -412,15 +411,18 @@ export class SocketServer {
412411
return;
413412
}
414413

414+
const statsErrors = getStatsErrors(statsJson as RsbuildStats) ?? [];
415+
const statsWarnings = getStatsWarnings(statsJson as RsbuildStats) ?? [];
416+
415417
if (statsJson.hash) {
416418
const prevHash = this.currentHash.get(token);
417419
this.currentHash.set(token, statsJson.hash);
418420

419421
// If build hash is not changed and there is no error or warning, skip emit
420422
const shouldEmit =
421423
!force &&
422-
!statsJson.errorsCount &&
423-
!statsJson.warningsCount &&
424+
statsErrors.length === 0 &&
425+
statsWarnings.length === 0 &&
424426
prevHash === statsJson.hash;
425427

426428
if (shouldEmit) {
@@ -437,8 +439,7 @@ export class SocketServer {
437439
);
438440
}
439441

440-
if (statsJson.errorsCount) {
441-
const statsErrors = getAllStatsErrors(statsJson) ?? [];
442+
if (statsErrors.length > 0) {
442443
const formattedErrors = statsErrors.map((item) => formatStatsError(item));
443444

444445
this.sockWrite(
@@ -454,8 +455,7 @@ export class SocketServer {
454455
return;
455456
}
456457

457-
if (statsJson.warningsCount) {
458-
const statsWarnings = getAllStatsWarnings(statsJson) ?? [];
458+
if (statsWarnings.length > 0) {
459459
const formattedWarnings = statsWarnings.map((item) =>
460460
formatStatsError(item),
461461
);

packages/core/src/types/rsbuild.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,3 +365,15 @@ export type RsbuildEntry = Record<
365365
>;
366366

367367
export type RsbuildMode = 'development' | 'production' | 'none';
368+
369+
export type RsbuildStatsItem = Pick<
370+
Rspack.StatsCompilation,
371+
'errors' | 'warnings' | 'time'
372+
>;
373+
374+
/**
375+
* A subset of Rspack's StatsCompilation with only the fields we need
376+
*/
377+
export type RsbuildStats = RsbuildStatsItem & {
378+
children: RsbuildStatsItem[];
379+
};

0 commit comments

Comments
 (0)