Skip to content

Commit 90c1534

Browse files
feat(core): support printFileSize.detail and printFileSize.total (#729)
Co-authored-by: neverland <[email protected]>
1 parent 1fd4fa8 commit 90c1534

File tree

6 files changed

+235
-44
lines changed

6 files changed

+235
-44
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@rsbuild/shared': patch
3+
'@rsbuild/core': patch
4+
---
5+
6+
feat(core): support printFileSize.detail and printFileSize.total
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { join } from 'path';
2+
import { expect, test } from '@playwright/test';
3+
import { build } from '@scripts/shared';
4+
5+
const cwd = join(__dirname, 'basic');
6+
7+
test.describe('should print file size correctly', async () => {
8+
let originalLog = console.log;
9+
let consoleOutput: string = '';
10+
11+
test.beforeEach(() => {
12+
consoleOutput = '';
13+
console.log = (...output) => (consoleOutput += output.join(' ') + '\n');
14+
});
15+
16+
test.afterEach(() => {
17+
console.log = originalLog;
18+
});
19+
20+
test('printFileSize: true should work', async () => {
21+
await build({
22+
cwd,
23+
rsbuildConfig: {
24+
performance: {
25+
printFileSize: true,
26+
},
27+
},
28+
});
29+
expect(consoleOutput).toContain('dist/static/js');
30+
expect(consoleOutput).toContain('Total size:');
31+
expect(consoleOutput).toContain('Gzipped size:');
32+
});
33+
34+
test('printFileSize: false should work', async () => {
35+
await build({
36+
cwd,
37+
rsbuildConfig: {
38+
performance: {
39+
printFileSize: false,
40+
},
41+
},
42+
});
43+
expect(consoleOutput).not.toContain('dist/static/js');
44+
expect(consoleOutput).not.toContain('Total size:');
45+
expect(consoleOutput).not.toContain('Gzipped size:');
46+
});
47+
48+
test('printFileSize.detail: false should work', async () => {
49+
await build({
50+
cwd,
51+
rsbuildConfig: {
52+
performance: {
53+
printFileSize: {
54+
detail: false,
55+
},
56+
},
57+
},
58+
});
59+
expect(consoleOutput).not.toContain('dist/static/js');
60+
expect(consoleOutput).toContain('Total size:');
61+
expect(consoleOutput).toContain('Gzipped size:');
62+
});
63+
64+
test('printFileSize.total: false should work', async () => {
65+
await build({
66+
cwd,
67+
rsbuildConfig: {
68+
performance: {
69+
printFileSize: {
70+
total: false,
71+
},
72+
},
73+
},
74+
});
75+
expect(consoleOutput).toContain('dist/static/js');
76+
expect(consoleOutput).not.toContain('Total size:');
77+
expect(consoleOutput).not.toContain('Gzipped size:');
78+
});
79+
});

packages/core/src/plugins/fileSize.ts

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
import path from 'path';
66
import { fse } from '@rsbuild/shared';
77
import { color, logger } from '@rsbuild/shared';
8-
import type { Stats, MultiStats, StatsAsset } from '@rsbuild/shared';
8+
import type {
9+
Stats,
10+
MultiStats,
11+
StatsAsset,
12+
PrintFileSizeOptions,
13+
} from '@rsbuild/shared';
914
import type { RsbuildPlugin } from '../types';
1015

1116
/** Filter source map and license files */
@@ -45,7 +50,15 @@ const calcFileSize = (len: number) => {
4550
return `${val.toFixed(val < 1 ? 2 : 1)} kB`;
4651
};
4752

48-
async function printFileSizes(stats: Stats | MultiStats, distPath: string) {
53+
async function printFileSizes(
54+
config: PrintFileSizeOptions,
55+
stats: Stats | MultiStats,
56+
distPath: string,
57+
) {
58+
if (config.detail === false && config.total === false) {
59+
return;
60+
}
61+
4962
const { default: gzipSize } = await import('@rsbuild/shared/gzip-size');
5063

5164
const formatAsset = (asset: StatsAsset) => {
@@ -92,14 +105,16 @@ async function printFileSizes(stats: Stats | MultiStats, distPath: string) {
92105

93106
assets.sort((a, b) => b.size - a.size);
94107

108+
logger.info(`Production file sizes:\n`);
109+
95110
const longestLabelLength = Math.max(...assets.map((a) => a.sizeLabel.length));
96111
const longestFileLength = Math.max(
97112
...assets.map((a) => (a.folder + path.sep + a.name).length),
98113
);
99114

100-
logger.info(`Production file sizes:\n`);
101-
102-
printHeader(longestFileLength, longestLabelLength);
115+
if (config.detail !== false) {
116+
printHeader(longestFileLength, longestLabelLength);
117+
}
103118

104119
let totalSize = 0;
105120
let totalGzipSize = 0;
@@ -113,41 +128,61 @@ async function printFileSizes(stats: Stats | MultiStats, distPath: string) {
113128
totalSize += asset.size;
114129
totalGzipSize += asset.gzippedSize;
115130

116-
if (sizeLength < longestLabelLength) {
117-
const rightPadding = ' '.repeat(longestLabelLength - sizeLength);
118-
sizeLabel += rightPadding;
119-
}
131+
if (config.detail !== false) {
132+
if (sizeLength < longestLabelLength) {
133+
const rightPadding = ' '.repeat(longestLabelLength - sizeLength);
134+
sizeLabel += rightPadding;
135+
}
120136

121-
let fileNameLabel =
122-
color.dim(asset.folder + path.sep) + color.cyan(asset.name);
137+
let fileNameLabel =
138+
color.dim(asset.folder + path.sep) + color.cyan(asset.name);
123139

124-
if (fileNameLength < longestFileLength) {
125-
const rightPadding = ' '.repeat(longestFileLength - fileNameLength);
126-
fileNameLabel += rightPadding;
127-
}
140+
if (fileNameLength < longestFileLength) {
141+
const rightPadding = ' '.repeat(longestFileLength - fileNameLength);
142+
fileNameLabel += rightPadding;
143+
}
128144

129-
logger.log(` ${fileNameLabel} ${sizeLabel} ${gzipSizeLabel}`);
145+
logger.log(` ${fileNameLabel} ${sizeLabel} ${gzipSizeLabel}`);
146+
}
130147
});
131148

132-
const totalSizeLabel = `${color.bold(
133-
color.blue('Total size:'),
134-
)} ${calcFileSize(totalSize)}`;
135-
const gzippedSizeLabel = `${color.bold(
136-
color.blue('Gzipped size:'),
137-
)} ${calcFileSize(totalGzipSize)}`;
138-
logger.log(`\n ${totalSizeLabel}\n ${gzippedSizeLabel}\n`);
149+
if (config.total !== false) {
150+
const totalSizeLabel = `${color.bold(
151+
color.blue('Total size:'),
152+
)} ${calcFileSize(totalSize)}`;
153+
const gzippedSizeLabel = `${color.bold(
154+
color.blue('Gzipped size:'),
155+
)} ${calcFileSize(totalGzipSize)}`;
156+
logger.log(`\n ${totalSizeLabel}\n ${gzippedSizeLabel}\n`);
157+
}
139158
}
140159

141160
export const pluginFileSize = (): RsbuildPlugin => ({
142161
name: 'rsbuild:file-size',
143162

144163
setup(api) {
145164
api.onAfterBuild(async ({ stats }) => {
146-
const config = api.getNormalizedConfig();
165+
const { printFileSize } = api.getNormalizedConfig().performance;
166+
167+
if (printFileSize === false) {
168+
return;
169+
}
170+
171+
const printFileSizeConfig =
172+
typeof printFileSize === 'boolean'
173+
? {
174+
total: true,
175+
detail: true,
176+
}
177+
: printFileSize;
147178

148-
if (config.performance.printFileSize && stats) {
179+
if (stats) {
149180
try {
150-
await printFileSizes(stats, api.context.distPath);
181+
await printFileSizes(
182+
printFileSizeConfig,
183+
stats,
184+
api.context.distPath,
185+
);
151186
} catch (err) {
152187
logger.warn('Failed to print file size.');
153188
logger.warn(err as Error);

packages/document/docs/en/shared/config/performance/printFileSize.md

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,54 @@
1-
- **Type:** `boolean`
1+
- **Type:**
2+
3+
```ts
4+
type PrintFileSizeOptions =
5+
| {
6+
/**
7+
* whether to print total size
8+
*/
9+
total?: boolean;
10+
/**
11+
* whether to print size of each file
12+
*/
13+
detail?: boolean;
14+
}
15+
| boolean;
16+
```
17+
218
- **Default:** `true`
319

420
Whether to print the file sizes after production build.
521

22+
If it is a Boolean type, it will be decided according to the config whether to print the file sizes. The default output is as follows.
23+
624
```bash
725
info Production file sizes:
826

9-
File Size Gzipped
10-
dist/static/js/lib-react.09721b5c.js 152.6 kB 49.0 kB
11-
dist/html/main/index.html 5.8 kB 2.5 kB
12-
dist/static/js/main.3568a38e.js 3.5 kB 1.4 kB
13-
dist/static/css/main.03221f72.css 1.4 kB 741 B
27+
File Size Gzipped
28+
dist/static/js/lib-react.b0714b60.js 140.4 kB 45.0 kB
29+
dist/static/js/index.f3fde9c7.js 1.9 kB 0.97 kB
30+
dist/index.html 0.39 kB 0.25 kB
31+
dist/static/css/index.2960ac62.css 0.35 kB 0.26 kB
32+
33+
Total size: 143.0 kB
34+
Gzipped size: 46.5 kB
1435
```
1536

16-
### Example
37+
You can also configure whether to print the sum of the size of all static resource files and whether to print the size of each static resource file through the Object type.
38+
39+
If you don't want to print the size of each static resource file, you can:
40+
41+
```ts
42+
export default {
43+
performance: {
44+
printFileSize: {
45+
detail: false,
46+
},
47+
},
48+
};
49+
```
1750

18-
Disable the logs:
51+
If you don't want to print any information, you can disable it by setting `printFileSize` to `false`:
1952

2053
```ts
2154
export default {

packages/document/docs/zh/shared/config/performance/printFileSize.md

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,54 @@
1-
- **类型:** `boolean`
1+
- **类型:**
2+
3+
```ts
4+
type PrintFileSizeOptions =
5+
| {
6+
/**
7+
* 是否输出所有静态资源文件的总体积
8+
*/
9+
total?: boolean;
10+
/**
11+
* 是否输出每个静态资源文件的体积
12+
*/
13+
detail?: boolean;
14+
}
15+
| boolean;
16+
```
17+
218
- **默认值:** `true`
319

420
是否在生产环境构建后输出所有静态资源文件的体积。
521

22+
如果是 Boolean 类型,将根据配置决定是否输出所有静态资源文件的体积,默认输出如下。
23+
624
```bash
725
info Production file sizes:
826

9-
File Size Gzipped
10-
dist/static/js/lib-react.09721b5c.js 152.6 kB 49.0 kB
11-
dist/html/main/index.html 5.8 kB 2.5 kB
12-
dist/static/js/main.3568a38e.js 3.5 kB 1.4 kB
13-
dist/static/css/main.03221f72.css 1.4 kB 741 B
27+
File Size Gzipped
28+
dist/static/js/lib-react.b0714b60.js 140.4 kB 45.0 kB
29+
dist/static/js/index.f3fde9c7.js 1.9 kB 0.97 kB
30+
dist/index.html 0.39 kB 0.25 kB
31+
dist/static/css/index.2960ac62.css 0.35 kB 0.26 kB
32+
33+
Total size: 143.0 kB
34+
Gzipped size: 46.5 kB
1435
```
1536

16-
### 示例
37+
你也可以通过 Object 类型分别对输出所有静态资源文件的体积和以及输出每个静态资源文件的体积进行配置。
38+
39+
如果你不想输出每个静态资源文件的体积,可以:
40+
41+
```ts
42+
export default {
43+
performance: {
44+
printFileSize: {
45+
detail: false,
46+
},
47+
},
48+
};
49+
```
1750

18-
禁用相关日志
51+
如果你不想输出任何信息,可以将 `printFileSize` 置为 `false` 将其禁用掉
1952

2053
```ts
2154
export default {

packages/shared/src/types/config/performance.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ export type BuildCacheOptions = {
1010
cacheDigest?: Array<string | undefined>;
1111
};
1212

13+
export type PrintFileSizeOptions = {
14+
total?: boolean;
15+
detail?: boolean;
16+
};
17+
1318
export interface PreconnectOption {
1419
href: string;
1520
crossorigin?: boolean;
@@ -58,7 +63,7 @@ export interface PerformanceConfig {
5863
/**
5964
* Whether to print the file sizes after production build.
6065
*/
61-
printFileSize?: boolean;
66+
printFileSize?: PrintFileSizeOptions | boolean;
6267
/**
6368
* Configure the chunk splitting strategy.
6469
*/
@@ -105,7 +110,7 @@ export interface PerformanceConfig {
105110
}
106111

107112
export interface NormalizedPerformanceConfig extends PerformanceConfig {
108-
printFileSize: boolean;
113+
printFileSize: PrintFileSizeOptions | boolean;
109114
buildCache: BuildCacheOptions | boolean;
110115
chunkSplit: RsbuildChunkSplit;
111116
}

0 commit comments

Comments
 (0)