Skip to content

Commit 9eb9a3d

Browse files
authored
perf: prebundle large dependencies (#1282)
1 parent b0f7800 commit 9eb9a3d

File tree

10 files changed

+539
-65
lines changed

10 files changed

+539
-65
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ dist/
88
dist-*
99
!**/rslog/dist
1010
coverage/
11+
compiled/
1112
doc_build/
1213
playwright-report/
1314
tsconfig.tsbuildinfo

packages/core/package.json

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,25 +71,26 @@
7171
"dev": "npm run start",
7272
"build": "rslib build",
7373
"start": "rslib build -w",
74-
"test": "rstest run"
74+
"test": "rstest run",
75+
"prebundle": "prebundle"
7576
},
7677
"dependencies": {
77-
"@rsbuild/plugin-check-syntax": "1.3.0",
7878
"@rsdoctor/graph": "workspace:*",
7979
"@rsdoctor/sdk": "workspace:*",
8080
"@rsdoctor/types": "workspace:*",
8181
"@rsdoctor/utils": "workspace:*",
82-
"axios": "^1.11.0",
8382
"browserslist-load-config": "^1.0.0",
84-
"enhanced-resolve": "5.12.0",
85-
"filesize": "^10.1.6",
8683
"fs-extra": "^11.1.1",
8784
"lodash-es": "^4.17.21",
88-
"path-browserify": "1.0.1",
8985
"semver": "^7.7.2",
9086
"source-map": "^0.7.4"
9187
},
9288
"devDependencies": {
89+
"@rsbuild/plugin-check-syntax": "1.3.0",
90+
"axios": "^1.11.0",
91+
"path-browserify": "1.0.1",
92+
"enhanced-resolve": "5.12.0",
93+
"filesize": "^10.1.6",
9394
"@rspack/core": "1.5.1",
9495
"@scripts/test-helper": "workspace:*",
9596
"@types/fs-extra": "^11.0.4",
@@ -100,6 +101,7 @@
100101
"@types/semver": "^7.7.0",
101102
"@types/tapable": "2.2.7",
102103
"babel-loader": "10.0.0",
104+
"prebundle": "1.4.1",
103105
"string-loader": "0.0.1",
104106
"ts-loader": "^9.5.2",
105107
"tslib": "2.8.1",

packages/core/rslib.config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import { defineConfig, rspack } from '@rslib/core';
22
import { dualPackageBundleless } from '../../scripts/rslib.base.config';
33

4+
const externals = [
5+
// Externalize workspace packages
6+
'@rsdoctor/graph',
7+
'@rsdoctor/sdk',
8+
'@rsdoctor/types',
9+
'@rsdoctor/utils',
10+
];
11+
412
export default defineConfig({
513
...dualPackageBundleless,
614
lib: [
@@ -15,6 +23,7 @@ export default defineConfig({
1523
filename: {
1624
js: '[name].js',
1725
},
26+
externals,
1827
},
1928
shims: {
2029
esm: {
@@ -33,6 +42,7 @@ export default defineConfig({
3342
filename: {
3443
js: '[name].cjs',
3544
},
45+
externals,
3646
},
3747
shims: {
3848
cjs: {

packages/sdk/package.json

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,35 +19,38 @@
1919
},
2020
"files": [
2121
"dist",
22-
"static"
22+
"static",
23+
"compiled"
2324
],
2425
"scripts": {
25-
"build": "rslib build",
26+
"build": "npm run prebundle && rslib build",
2627
"dev": "npm run start",
2728
"start": "rslib build -w",
28-
"test": "rstest run"
29+
"test": "rstest run",
30+
"prebundle": "prebundle"
2931
},
3032
"dependencies": {
3133
"@rsdoctor/client": "workspace:*",
3234
"@rsdoctor/graph": "workspace:*",
3335
"@rsdoctor/types": "workspace:*",
3436
"@rsdoctor/utils": "workspace:*",
3537
"@types/fs-extra": "^11.0.4",
38+
"socket.io": "4.8.1",
39+
"tapable": "2.2.2"
40+
},
41+
"devDependencies": {
3642
"body-parser": "1.20.3",
3743
"cors": "2.8.5",
3844
"dayjs": "1.11.13",
3945
"fs-extra": "^11.1.1",
4046
"json-cycle": "^1.5.0",
4147
"open": "^10.2.0",
4248
"sirv": "2.0.4",
43-
"socket.io": "4.8.1",
4449
"source-map": "^0.7.4",
45-
"tapable": "2.2.2"
46-
},
47-
"devDependencies": {
4850
"@types/body-parser": "1.19.6",
4951
"@types/cors": "2.8.19",
5052
"@types/node": "^22.8.1",
53+
"prebundle": "1.4.1",
5154
"tslib": "2.8.1",
5255
"typescript": "^5.9.2"
5356
},

packages/sdk/prebundle.config.mjs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
export default {
2+
dependencies: ['body-parser', 'cors', 'dayjs', 'fs-extra', 'json-cycle'],
3+
exclude: [
4+
'@rsdoctor/client',
5+
'@rsdoctor/graph',
6+
'@rsdoctor/types',
7+
'@rsdoctor/utils',
8+
],
9+
10+
build: {
11+
platform: 'node',
12+
target: 'node16',
13+
format: 'cjs',
14+
minify: false,
15+
sourcemap: false,
16+
metafile: false,
17+
write: true,
18+
output: {
19+
chunkFormat: 'commonjs',
20+
},
21+
environment: {
22+
node: true,
23+
},
24+
},
25+
26+
output: {
27+
dir: './compiled',
28+
filename: '[name].cjs',
29+
},
30+
31+
resolve: {
32+
extensions: ['.js', '.json', '.ts', '.tsx'],
33+
},
34+
};

packages/sdk/rslib.config.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,45 @@
1+
import { defineConfig } from '@rslib/core';
2+
import { join } from 'path';
13
import { dualPackage } from '../../scripts/rslib.base.config';
24

3-
export default dualPackage;
5+
const prebundleConfigPath = join(__dirname, './prebundle.config.mjs');
6+
const prebundleConfigModule = await import(prebundleConfigPath);
7+
const prebundleConfig = prebundleConfigModule.default;
8+
const regexpMap: Record<string, RegExp> = {};
9+
10+
for (const item of prebundleConfig.dependencies) {
11+
const depName = typeof item === 'string' ? item : item.name;
12+
if (typeof item !== 'string' && item.dtsOnly) {
13+
continue;
14+
}
15+
16+
regexpMap[depName] = new RegExp(`compiled[\\/]${depName}(?:[\\/]|$)`);
17+
}
18+
19+
const externals = [
20+
({ request }: { request?: string }, callback: any) => {
21+
if (request) {
22+
if (prebundleConfig.dependencies.includes(request)) {
23+
return callback(undefined, `../compiled/${request}/index.js`);
24+
}
25+
const entries = Object.entries(regexpMap);
26+
for (const [name, test] of entries) {
27+
if (test.test(request)) {
28+
return callback(undefined, `../compiled/${name}/index.js`);
29+
}
30+
}
31+
}
32+
callback();
33+
},
34+
];
35+
36+
export default defineConfig({
37+
...dualPackage,
38+
lib: dualPackage.lib.map((libConfig) => ({
39+
...libConfig,
40+
output: {
41+
...libConfig.output,
42+
externals,
43+
},
44+
})),
45+
});

packages/utils/package.json

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,15 @@
5858
"module": "dist/build.js",
5959
"types": "dist/build/index.d.ts",
6060
"files": [
61-
"dist"
61+
"dist",
62+
"compiled"
6263
],
6364
"scripts": {
64-
"build": "rslib build",
65+
"build": "npm run prebundle && rslib build",
6566
"dev": "npm run start",
6667
"start": "rslib build -w",
67-
"test": "rstest run"
68+
"test": "rstest run",
69+
"prebundle": "prebundle"
6870
},
6971
"dependencies": {
7072
"@babel/code-frame": "7.26.2",
@@ -73,10 +75,8 @@
7375
"acorn": "^8.10.0",
7476
"acorn-import-attributes": "^1.9.5",
7577
"acorn-walk": "8.3.4",
76-
"connect": "3.7.0",
7778
"deep-eql": "4.1.4",
7879
"envinfo": "7.14.0",
79-
"filesize": "^10.1.6",
8080
"fs-extra": "^11.1.1",
8181
"get-port": "5.1.1",
8282
"json-stream-stringify": "3.0.1",
@@ -92,6 +92,9 @@
9292
"@types/envinfo": "7.8.4",
9393
"@types/fs-extra": "^11.0.4",
9494
"@types/node": "^22.8.1",
95+
"prebundle": "1.4.1",
96+
"filesize": "^10.1.6",
97+
"connect": "3.7.0",
9598
"tslib": "2.8.1",
9699
"typescript": "^5.9.2"
97100
},
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
export default {
2+
dependencies: ['connect', 'filesize'],
3+
exclude: ['@rsdoctor/types'],
4+
5+
build: {
6+
platform: 'node',
7+
target: 'node16',
8+
format: 'cjs',
9+
minify: false,
10+
sourcemap: false,
11+
metafile: false,
12+
write: true,
13+
},
14+
15+
output: {
16+
dir: './compiled',
17+
filename: '[name].cjs',
18+
},
19+
20+
resolve: {
21+
extensions: ['.js', '.json', '.ts', '.tsx'],
22+
},
23+
};

packages/utils/rslib.config.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,41 @@
11
import { defineConfig } from '@rslib/core';
2+
import { join } from 'path';
23
import { dualPackage } from '../../scripts/rslib.base.config';
34

5+
const prebundleConfigPath = join(__dirname, 'prebundle.config.mjs');
6+
const prebundleConfigModule = await import(prebundleConfigPath);
7+
const prebundleConfig = prebundleConfigModule.default;
8+
const regexpMap: Record<string, RegExp> = {};
9+
10+
for (const item of prebundleConfig.dependencies) {
11+
const depName = typeof item === 'string' ? item : item.name;
12+
13+
if (typeof item !== 'string' && item.dtsOnly) {
14+
continue;
15+
}
16+
17+
regexpMap[depName] = new RegExp(`compiled[\\/]${depName}(?:[\\/]|$)`);
18+
}
19+
20+
const externals = [
21+
'@rsdoctor/types',
22+
({ request }: { request?: string }, callback: any) => {
23+
if (request) {
24+
if (prebundleConfig.dependencies.includes(request)) {
25+
return callback(undefined, `../compiled/${request}/index.js`);
26+
}
27+
28+
const entries = Object.entries(regexpMap);
29+
for (const [name, test] of entries) {
30+
if (test.test(request)) {
31+
return callback(undefined, `../compiled/${name}/index.js`);
32+
}
33+
}
34+
}
35+
callback();
36+
},
37+
];
38+
439
export default defineConfig({
540
...dualPackage,
641
source: {
@@ -12,4 +47,11 @@ export default defineConfig({
1247
logger: './src/logger.ts',
1348
},
1449
},
50+
lib: dualPackage.lib.map((libConfig) => ({
51+
...libConfig,
52+
output: {
53+
...libConfig.output,
54+
externals,
55+
},
56+
})),
1557
});

0 commit comments

Comments
 (0)