Skip to content

Commit 616d7d5

Browse files
authored
feat: allow to filter files included in the manifest (#4307)
1 parent f0a4162 commit 616d7d5

File tree

8 files changed

+203
-19
lines changed

8 files changed

+203
-19
lines changed

e2e/cases/output/manifest-async-chunks/index.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ test('should generate manifest for async chunks correctly', async () => {
99
rsbuildConfig: {
1010
output: {
1111
manifest: true,
12-
legalComments: 'none',
1312
filenameHash: false,
1413
},
1514
performance: {

e2e/cases/output/manifest-generate/index.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ const rsbuildConfig: RsbuildConfig = {
1515
};
1616
},
1717
},
18-
legalComments: 'none',
1918
sourceMap: false,
2019
filenameHash: false,
2120
},

e2e/cases/output/manifest/index.test.ts

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
import { readFileSync } from 'node:fs';
22
import { join } from 'node:path';
3-
import { build, dev } from '@e2e/helper';
3+
import { build, dev, rspackOnlyTest } from '@e2e/helper';
44
import { expect, test } from '@playwright/test';
55

66
const fixtures = __dirname;
77

8-
test('output.manifest', async () => {
8+
test('should generate manifest file in output', async () => {
99
const rsbuild = await build({
1010
cwd: fixtures,
1111
rsbuildConfig: {
1212
output: {
1313
manifest: true,
14-
legalComments: 'none',
1514
filenameHash: false,
1615
},
1716
performance: {
@@ -42,13 +41,12 @@ test('output.manifest', async () => {
4241
});
4342
});
4443

45-
test('output.manifest set a path', async () => {
44+
test('should generate manifest file at specified path', async () => {
4645
await build({
4746
cwd: fixtures,
4847
rsbuildConfig: {
4948
output: {
5049
manifest: './custom/my-manifest.json',
51-
legalComments: 'none',
5250
filenameHash: false,
5351
},
5452
performance: {
@@ -69,7 +67,7 @@ test('output.manifest set a path', async () => {
6967
expect(Object.keys(parsed.allFiles).length).toBe(2);
7068
});
7169

72-
test('output.manifest when target is node', async () => {
70+
test('should generate manifest file when target is node', async () => {
7371
const rsbuild = await build({
7472
cwd: fixtures,
7573
rsbuildConfig: {
@@ -79,14 +77,8 @@ test('output.manifest when target is node', async () => {
7977
},
8078
target: 'node',
8179
manifest: true,
82-
legalComments: 'none',
8380
filenameHash: false,
8481
},
85-
performance: {
86-
chunkSplit: {
87-
strategy: 'all-in-one',
88-
},
89-
},
9082
},
9183
});
9284

@@ -109,7 +101,7 @@ test('output.manifest when target is node', async () => {
109101
});
110102
});
111103

112-
test('output.manifest should always write to disk when dev', async ({
104+
test('should always write manifest to disk when in dev mode', async ({
113105
page,
114106
}) => {
115107
const rsbuild = await dev({
@@ -121,7 +113,6 @@ test('output.manifest should always write to disk when dev', async ({
121113
root: 'dist-dev',
122114
},
123115
manifest: true,
124-
legalComments: 'none',
125116
filenameHash: false,
126117
},
127118
performance: {
@@ -141,3 +132,75 @@ test('output.manifest should always write to disk when dev', async ({
141132

142133
await rsbuild.close();
143134
});
135+
136+
test('should allow to filter files in manifest', async () => {
137+
const rsbuild = await build({
138+
cwd: fixtures,
139+
rsbuildConfig: {
140+
output: {
141+
manifest: {
142+
filter: (file) => file.name.endsWith('.js'),
143+
},
144+
filenameHash: false,
145+
},
146+
performance: {
147+
chunkSplit: {
148+
strategy: 'all-in-one',
149+
},
150+
},
151+
},
152+
});
153+
154+
const files = await rsbuild.unwrapOutputJSON();
155+
156+
const manifestContent =
157+
files[Object.keys(files).find((file) => file.endsWith('manifest.json'))!];
158+
const manifest = JSON.parse(manifestContent);
159+
160+
// main.js
161+
expect(Object.keys(manifest.allFiles).length).toBe(1);
162+
163+
expect(manifest.entries.index).toMatchObject({
164+
initial: {
165+
js: ['/static/js/index.js'],
166+
},
167+
});
168+
});
169+
170+
rspackOnlyTest(
171+
'should allow to include license files in manifest',
172+
async () => {
173+
const rsbuild = await build({
174+
cwd: fixtures,
175+
rsbuildConfig: {
176+
output: {
177+
manifest: {
178+
filter: () => true,
179+
},
180+
filenameHash: false,
181+
},
182+
performance: {
183+
chunkSplit: {
184+
strategy: 'all-in-one',
185+
},
186+
},
187+
},
188+
});
189+
190+
const files = await rsbuild.unwrapOutputJSON();
191+
192+
const manifestContent =
193+
files[Object.keys(files).find((file) => file.endsWith('manifest.json'))!];
194+
const manifest = JSON.parse(manifestContent);
195+
196+
expect(Object.keys(manifest.allFiles).length).toBe(3);
197+
198+
expect(manifest.entries.index).toMatchObject({
199+
initial: {
200+
js: ['/static/js/index.js'],
201+
},
202+
html: ['/index.html'],
203+
assets: ['/static/js/index.js.LICENSE.txt'],
204+
});
205+
},
206+
);
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
console.log('hello!');
1+
import React from 'react';
2+
3+
console.log('hello!', React);

packages/core/src/plugins/manifest.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { FileDescriptor } from 'rspack-manifest-plugin';
1+
import type { FileDescriptor } from '../../compiled/rspack-manifest-plugin';
22
import { isObject } from '../helpers';
33
import { recursiveChunkEntryNames } from '../rspack/preload/helpers';
44
import type {
@@ -175,9 +175,15 @@ export const pluginManifest = (): RsbuildPlugin => ({
175175
);
176176
const { htmlPaths } = environment;
177177

178+
// Exclude `*.LICENSE.txt` files by default
179+
const filter =
180+
manifestOptions.filter ??
181+
((file: FileDescriptor) => !file.name.endsWith('.LICENSE.txt'));
182+
178183
chain.plugin(CHAIN_ID.PLUGIN.MANIFEST).use(RspackManifestPlugin, [
179184
{
180185
fileName: manifestOptions.filename,
186+
filter,
181187
writeToFileEmit: isDev && writeToDisk !== true,
182188
generate: generateManifest(htmlPaths, manifestOptions),
183189
},

packages/core/src/types/config.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import type {
1919
Filter as ProxyFilter,
2020
} from '../../compiled/http-proxy-middleware/index.js';
2121
import type RspackChain from '../../compiled/rspack-chain/index.js';
22+
import type { FileDescriptor } from '../../compiled/rspack-manifest-plugin';
2223
import type { BundleAnalyzerPlugin } from '../../compiled/webpack-bundle-analyzer/index.js';
2324
import type {
2425
ModifyBundlerChainUtils,
@@ -926,9 +927,15 @@ export type ManifestObjectConfig = {
926927
* A custom function to generate the content of the manifest file.
927928
*/
928929
generate?: (params: {
929-
files: import('rspack-manifest-plugin').FileDescriptor[];
930+
files: FileDescriptor[];
930931
manifestData: ManifestData;
931932
}) => Record<string, unknown>;
933+
/**
934+
* Allows you to filter the files included in the manifest.
935+
* The function receives a `file` parameter and returns `true` to keep the file, or `false` to exclude it.
936+
* @default (file: FileDescriptor) => !file.name.endsWith('.LICENSE.txt')
937+
*/
938+
filter?: (file: FileDescriptor) => boolean;
932939
};
933940

934941
export type ManifestConfig = string | boolean | ManifestObjectConfig;

website/docs/en/config/output/manifest.mdx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,57 @@ const files = [
184184
},
185185
];
186186
```
187+
188+
### filter
189+
190+
- **Type:**
191+
192+
```ts
193+
type ManifestFilter = (file: FileDescriptor) => boolean;
194+
```
195+
196+
- **Default:** `file => !file.name.endsWith('.LICENSE.txt')`
197+
- **Version:** `>= 1.2.0`
198+
199+
Allows you to filter the files included in the manifest. The function receives a `file` parameter and returns `true` to keep the file, or `false` to exclude it.
200+
201+
By default, `*.LICENSE.txt` files are excluded from the manifest, as these license files are only used to declare open source licenses and are not used at runtime.
202+
203+
For example, to only keep `*.js` files:
204+
205+
```ts title="rsbuild.config.ts"
206+
export default {
207+
output: {
208+
manifest: {
209+
filter: (file) => file.name.endsWith('.js'),
210+
},
211+
},
212+
};
213+
```
214+
215+
The generated manifest file will only include `*.js` files:
216+
217+
```json title="dist/manifest.json"
218+
{
219+
"allFiles": ["/static/js/index.[hash].js"],
220+
"entries": {
221+
"index": {
222+
"initial": {
223+
"js": ["/static/js/index.[hash].js"]
224+
}
225+
}
226+
}
227+
}
228+
```
229+
230+
Or include all files:
231+
232+
```ts title="rsbuild.config.ts"
233+
export default {
234+
output: {
235+
manifest: {
236+
filter: () => true,
237+
},
238+
},
239+
};
240+
```

website/docs/zh/config/output/manifest.mdx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,57 @@ const files = [
184184
},
185185
];
186186
```
187+
188+
### filter
189+
190+
- **类型:**
191+
192+
```ts
193+
type ManifestFilter = (file: FileDescriptor) => boolean;
194+
```
195+
196+
- **默认值:** `file => !file.name.endsWith('.LICENSE.txt')`
197+
- **版本:** `>= 1.2.0`
198+
199+
允许你过滤包含在 manifest 中的文件。该函数接收一个 `file` 参数,返回 `true` 表示保留该文件,返回 `false` 表示不保留该文件。
200+
201+
默认情况下,`*.LICENSE.txt` 文件不会被包含在 manifest 文件中,因为这些许可证文件仅用于声明开源协议,不会在运行时被使用。
202+
203+
例如,仅保留 `*.js` 文件:
204+
205+
```ts title="rsbuild.config.ts"
206+
export default {
207+
output: {
208+
manifest: {
209+
filter: (file) => file.name.endsWith('.js'),
210+
},
211+
},
212+
};
213+
```
214+
215+
生成的 manifest 文件中仅会包含 `*.js` 文件:
216+
217+
```json title="dist/manifest.json"
218+
{
219+
"allFiles": ["/static/js/index.[hash].js"],
220+
"entries": {
221+
"index": {
222+
"initial": {
223+
"js": ["/static/js/index.[hash].js"]
224+
}
225+
}
226+
}
227+
}
228+
```
229+
230+
或者是包含所有文件:
231+
232+
```ts title="rsbuild.config.ts"
233+
export default {
234+
output: {
235+
manifest: {
236+
filter: () => true,
237+
},
238+
},
239+
};
240+
```

0 commit comments

Comments
 (0)