@esmx/rspack 3.0.0-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/dist/app.d.ts +160 -0
- package/dist/app.mjs +130 -0
- package/dist/build-target.d.ts +8 -0
- package/dist/build-target.mjs +0 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.mjs +142 -0
- package/dist/html-app.d.ts +299 -0
- package/dist/html-app.mjs +214 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.mjs +7 -0
- package/dist/loader.d.ts +30 -0
- package/dist/loader.mjs +33 -0
- package/dist/pack.d.ts +2 -0
- package/dist/pack.mjs +69 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.mjs +1 -0
- package/dist/utils/rsbuild.d.ts +12 -0
- package/dist/utils/rsbuild.mjs +97 -0
- package/package.json +108 -0
- package/src/app.ts +319 -0
- package/src/build-target.ts +8 -0
- package/src/config.ts +171 -0
- package/src/html-app.ts +560 -0
- package/src/index.ts +12 -0
- package/src/loader.ts +34 -0
- package/src/pack.ts +79 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/rsbuild.ts +105 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { styleText } from "node:util";
|
|
2
|
+
import { rspack } from "@rspack/core";
|
|
3
|
+
export function createRsBuild(options) {
|
|
4
|
+
const multiCompiler = rspack(options);
|
|
5
|
+
return {
|
|
6
|
+
get compilers() {
|
|
7
|
+
return multiCompiler.compilers;
|
|
8
|
+
},
|
|
9
|
+
build() {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
multiCompiler.run((err, stats) => {
|
|
12
|
+
if (err) {
|
|
13
|
+
return resolve(false);
|
|
14
|
+
}
|
|
15
|
+
if (stats?.hasErrors()) {
|
|
16
|
+
stats.toJson({ errors: true })?.errors?.forEach((err2) => {
|
|
17
|
+
console.log(styleText("red", err2.message));
|
|
18
|
+
});
|
|
19
|
+
return resolve(false);
|
|
20
|
+
}
|
|
21
|
+
multiCompiler.close((err2) => {
|
|
22
|
+
if (err2) {
|
|
23
|
+
console.log(styleText("red", err2.message));
|
|
24
|
+
return resolve(false);
|
|
25
|
+
}
|
|
26
|
+
process.nextTick(() => {
|
|
27
|
+
resolve(true);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
watch() {
|
|
34
|
+
const watching = multiCompiler.watch({}, (err, stats) => {
|
|
35
|
+
if (err) {
|
|
36
|
+
console.error(err);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (stats?.hasErrors()) {
|
|
40
|
+
stats.toJson({ errors: true })?.errors?.forEach((err2) => {
|
|
41
|
+
console.log(styleText("red", err2.message));
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
const signals = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
46
|
+
signals.forEach((signal) => {
|
|
47
|
+
process.on(signal, () => {
|
|
48
|
+
watching.close(() => {
|
|
49
|
+
process.exit();
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
process.on("uncaughtException", handleExit);
|
|
54
|
+
process.on("unhandledRejection", handleExit);
|
|
55
|
+
function handleExit(err) {
|
|
56
|
+
console.error(err);
|
|
57
|
+
watching.close(() => {
|
|
58
|
+
process.exit(1);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export class RsBuild {
|
|
65
|
+
compiler;
|
|
66
|
+
constructor(options) {
|
|
67
|
+
this.compiler = rspack(options);
|
|
68
|
+
}
|
|
69
|
+
async build() {
|
|
70
|
+
return new Promise((resolve) => {
|
|
71
|
+
this.compiler.run((err, stats) => {
|
|
72
|
+
if (err) {
|
|
73
|
+
return resolve(false);
|
|
74
|
+
}
|
|
75
|
+
if (stats?.hasErrors()) {
|
|
76
|
+
stats.toJson({ errors: true })?.errors?.forEach((err2) => {
|
|
77
|
+
console.error(err2);
|
|
78
|
+
});
|
|
79
|
+
return resolve(false);
|
|
80
|
+
}
|
|
81
|
+
this.compiler.close((err2) => {
|
|
82
|
+
if (err2) {
|
|
83
|
+
console.error(err2);
|
|
84
|
+
return resolve(false);
|
|
85
|
+
}
|
|
86
|
+
process.nextTick(() => {
|
|
87
|
+
resolve(true);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
watch() {
|
|
94
|
+
const watching = this.compiler.watch({}, () => {
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@esmx/rspack",
|
|
3
|
+
"description": "A high-performance Rspack integration for Esmx microfrontend framework, providing module federation and SSR capabilities.",
|
|
4
|
+
"author": {
|
|
5
|
+
"name": "lzxb",
|
|
6
|
+
"url": "https://github.com/lzxb"
|
|
7
|
+
},
|
|
8
|
+
"contributors": [
|
|
9
|
+
{
|
|
10
|
+
"name": "RockShi1994",
|
|
11
|
+
"url": "https://github.com/RockShi1994"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "jerrychan7",
|
|
15
|
+
"url": "https://github.com/jerrychan7"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/js-esm/esmx.git",
|
|
21
|
+
"directory": "packages/rspack"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/js-esm/esmx",
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/js-esm/esmx/issues"
|
|
26
|
+
},
|
|
27
|
+
"template": "library-node",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"keywords": [
|
|
30
|
+
"Rspack",
|
|
31
|
+
"TypeScript",
|
|
32
|
+
"JavaScript",
|
|
33
|
+
"CSS",
|
|
34
|
+
"Less",
|
|
35
|
+
"High Performance",
|
|
36
|
+
"Build Tool",
|
|
37
|
+
"Module Federation",
|
|
38
|
+
"SSR",
|
|
39
|
+
"Development Experience"
|
|
40
|
+
],
|
|
41
|
+
"scripts": {
|
|
42
|
+
"lint:js": "biome check --write --no-errors-on-unmatched",
|
|
43
|
+
"lint:css": "stylelint '**/*.{css,vue}' --fix --aei",
|
|
44
|
+
"lint:type": "tsc --noEmit",
|
|
45
|
+
"test": "vitest run --pass-with-no-tests",
|
|
46
|
+
"coverage": "vitest run --coverage --pass-with-no-tests",
|
|
47
|
+
"build": "unbuild"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@esmx/core": "*",
|
|
51
|
+
"less": "*"
|
|
52
|
+
},
|
|
53
|
+
"peerDependenciesMeta": {
|
|
54
|
+
"less": {
|
|
55
|
+
"optional": true
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"@esmx/import": "3.0.0-rc.10",
|
|
60
|
+
"@esmx/rspack-module-link-plugin": "3.0.0-rc.10",
|
|
61
|
+
"@npmcli/arborist": "^8.0.0",
|
|
62
|
+
"@rspack/core": "1.2.8",
|
|
63
|
+
"css-loader": "^7.1.2",
|
|
64
|
+
"less-loader": "^12.2.0",
|
|
65
|
+
"node-polyfill-webpack-plugin": "^4.1.0",
|
|
66
|
+
"pacote": "^21.0.0",
|
|
67
|
+
"style-loader": "^4.0.0",
|
|
68
|
+
"style-resources-loader": "^1.5.0",
|
|
69
|
+
"webpack-hot-middleware": "^2.26.1",
|
|
70
|
+
"webpack-node-externals": "~3.0.0",
|
|
71
|
+
"worker-rspack-loader": "^3.1.2"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@biomejs/biome": "1.9.4",
|
|
75
|
+
"@esmx/core": "3.0.0-rc.10",
|
|
76
|
+
"@esmx/lint": "3.0.0-rc.10",
|
|
77
|
+
"@types/node": "22.13.10",
|
|
78
|
+
"@types/npmcli__arborist": "^5.6.11",
|
|
79
|
+
"@types/pacote": "^11.1.8",
|
|
80
|
+
"@types/webpack-hot-middleware": "^2.25.9",
|
|
81
|
+
"@types/webpack-node-externals": "^3.0.4",
|
|
82
|
+
"@vitest/coverage-v8": "3.0.8",
|
|
83
|
+
"stylelint": "16.15.0",
|
|
84
|
+
"typescript": "5.8.2",
|
|
85
|
+
"unbuild": "2.0.0",
|
|
86
|
+
"vitest": "3.0.8"
|
|
87
|
+
},
|
|
88
|
+
"version": "3.0.0-rc.10",
|
|
89
|
+
"type": "module",
|
|
90
|
+
"private": false,
|
|
91
|
+
"exports": {
|
|
92
|
+
".": {
|
|
93
|
+
"import": "./dist/index.mjs",
|
|
94
|
+
"types": "./dist/index.d.ts"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"module": "dist/index.mjs",
|
|
98
|
+
"types": "./dist/index.d.ts",
|
|
99
|
+
"files": [
|
|
100
|
+
"lib",
|
|
101
|
+
"src",
|
|
102
|
+
"dist",
|
|
103
|
+
"*.mjs",
|
|
104
|
+
"template",
|
|
105
|
+
"public"
|
|
106
|
+
],
|
|
107
|
+
"gitHead": "4a528ffecfdc6f2c6e7d97bc952427745f467691"
|
|
108
|
+
}
|
package/src/app.ts
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { styleText } from 'node:util';
|
|
4
|
+
import {
|
|
5
|
+
type App,
|
|
6
|
+
type Esmx,
|
|
7
|
+
type Middleware,
|
|
8
|
+
PathType,
|
|
9
|
+
RenderContext,
|
|
10
|
+
type RenderContextOptions,
|
|
11
|
+
type ServerRenderHandle,
|
|
12
|
+
createApp,
|
|
13
|
+
mergeMiddlewares
|
|
14
|
+
} from '@esmx/core';
|
|
15
|
+
import { createVmImport } from '@esmx/import';
|
|
16
|
+
import type { RspackOptions } from '@rspack/core';
|
|
17
|
+
import hotMiddleware from 'webpack-hot-middleware';
|
|
18
|
+
import type { BuildTarget } from './build-target';
|
|
19
|
+
import { createRspackConfig } from './config';
|
|
20
|
+
import { pack } from './pack';
|
|
21
|
+
import { createRsBuild } from './utils';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Rspack 应用配置上下文接口。
|
|
25
|
+
*
|
|
26
|
+
* 该接口提供了在配置钩子函数中可以访问的上下文信息,允许你:
|
|
27
|
+
* - 访问 Esmx 框架实例
|
|
28
|
+
* - 获取当前的构建目标(client/server/node)
|
|
29
|
+
* - 修改 Rspack 配置
|
|
30
|
+
* - 访问应用选项
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* // entry.node.ts
|
|
35
|
+
* export default {
|
|
36
|
+
* async devApp(esmx) {
|
|
37
|
+
* return import('@esmx/rspack').then((m) =>
|
|
38
|
+
* m.createRspackApp(esmx, {
|
|
39
|
+
* // 配置钩子函数
|
|
40
|
+
* config(context) {
|
|
41
|
+
* // 访问构建目标
|
|
42
|
+
* if (context.buildTarget === 'client') {
|
|
43
|
+
* // 修改客户端构建配置
|
|
44
|
+
* context.config.optimization = {
|
|
45
|
+
* ...context.config.optimization,
|
|
46
|
+
* splitChunks: {
|
|
47
|
+
* chunks: 'all'
|
|
48
|
+
* }
|
|
49
|
+
* };
|
|
50
|
+
* }
|
|
51
|
+
* }
|
|
52
|
+
* })
|
|
53
|
+
* );
|
|
54
|
+
* }
|
|
55
|
+
* };
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export interface RspackAppConfigContext {
|
|
59
|
+
/**
|
|
60
|
+
* Esmx 框架实例。
|
|
61
|
+
* 可用于访问框架提供的 API 和工具函数。
|
|
62
|
+
*/
|
|
63
|
+
esmx: Esmx;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 当前的构建目标。
|
|
67
|
+
* - 'client': 客户端构建,生成浏览器可执行的代码
|
|
68
|
+
* - 'server': 服务端构建,生成 SSR 渲染代码
|
|
69
|
+
* - 'node': Node.js 构建,生成服务器入口代码
|
|
70
|
+
*/
|
|
71
|
+
buildTarget: BuildTarget;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Rspack 编译配置对象。
|
|
75
|
+
* 你可以在配置钩子中修改这个对象来自定义构建行为。
|
|
76
|
+
*/
|
|
77
|
+
config: RspackOptions;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 创建应用时传入的选项对象。
|
|
81
|
+
*/
|
|
82
|
+
options: RspackAppOptions;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Rspack 应用配置选项接口。
|
|
87
|
+
*
|
|
88
|
+
* 该接口提供了创建 Rspack 应用时可以使用的配置选项,包括:
|
|
89
|
+
* - 代码压缩选项
|
|
90
|
+
* - Rspack 配置钩子函数
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* // entry.node.ts
|
|
95
|
+
* export default {
|
|
96
|
+
* async devApp(esmx) {
|
|
97
|
+
* return import('@esmx/rspack').then((m) =>
|
|
98
|
+
* m.createRspackApp(esmx, {
|
|
99
|
+
* // 禁用代码压缩
|
|
100
|
+
* minimize: false,
|
|
101
|
+
* // 自定义 Rspack 配置
|
|
102
|
+
* config(context) {
|
|
103
|
+
* if (context.buildTarget === 'client') {
|
|
104
|
+
* context.config.optimization.splitChunks = {
|
|
105
|
+
* chunks: 'all'
|
|
106
|
+
* };
|
|
107
|
+
* }
|
|
108
|
+
* }
|
|
109
|
+
* })
|
|
110
|
+
* );
|
|
111
|
+
* }
|
|
112
|
+
* };
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export interface RspackAppOptions {
|
|
116
|
+
/**
|
|
117
|
+
* 是否启用代码压缩。
|
|
118
|
+
*
|
|
119
|
+
* - true: 启用代码压缩
|
|
120
|
+
* - false: 禁用代码压缩
|
|
121
|
+
* - undefined: 根据环境自动判断(生产环境启用,开发环境禁用)
|
|
122
|
+
*
|
|
123
|
+
* @default undefined
|
|
124
|
+
*/
|
|
125
|
+
minimize?: boolean;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Rspack 配置钩子函数。
|
|
129
|
+
*
|
|
130
|
+
* 在构建开始前调用,可以通过该函数修改 Rspack 的编译配置。
|
|
131
|
+
* 支持针对不同的构建目标(client/server/node)进行差异化配置。
|
|
132
|
+
*
|
|
133
|
+
* @param context - 配置上下文,包含框架实例、构建目标和配置对象
|
|
134
|
+
*/
|
|
135
|
+
config?: (context: RspackAppConfigContext) => void;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* 创建 Rspack 应用实例。
|
|
140
|
+
*
|
|
141
|
+
* 该函数根据运行环境(开发/生产)创建不同的应用实例:
|
|
142
|
+
* - 开发环境:配置热更新中间件和实时渲染
|
|
143
|
+
* - 生产环境:配置构建任务
|
|
144
|
+
*
|
|
145
|
+
* @param esmx - Esmx 框架实例
|
|
146
|
+
* @param options - Rspack 应用配置选项
|
|
147
|
+
* @returns 返回应用实例
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```ts
|
|
151
|
+
* // entry.node.ts
|
|
152
|
+
* export default {
|
|
153
|
+
* async devApp(esmx) {
|
|
154
|
+
* return import('@esmx/rspack').then((m) =>
|
|
155
|
+
* m.createRspackApp(esmx, {
|
|
156
|
+
* config(context) {
|
|
157
|
+
* // 配置 loader 处理不同类型的文件
|
|
158
|
+
* context.config.module = {
|
|
159
|
+
* rules: [
|
|
160
|
+
* {
|
|
161
|
+
* test: /\.ts$/,
|
|
162
|
+
* exclude: [/node_modules/],
|
|
163
|
+
* loader: 'builtin:swc-loader',
|
|
164
|
+
* options: {
|
|
165
|
+
* jsc: {
|
|
166
|
+
* parser: {
|
|
167
|
+
* syntax: 'typescript'
|
|
168
|
+
* }
|
|
169
|
+
* }
|
|
170
|
+
* }
|
|
171
|
+
* },
|
|
172
|
+
* {
|
|
173
|
+
* test: /\.css$/,
|
|
174
|
+
* use: ['style-loader', 'css-loader']
|
|
175
|
+
* }
|
|
176
|
+
* ]
|
|
177
|
+
* };
|
|
178
|
+
* }
|
|
179
|
+
* })
|
|
180
|
+
* );
|
|
181
|
+
* }
|
|
182
|
+
* };
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
export async function createRspackApp(
|
|
186
|
+
esmx: Esmx,
|
|
187
|
+
options?: RspackAppOptions
|
|
188
|
+
): Promise<App> {
|
|
189
|
+
const app = await createApp(esmx, esmx.command);
|
|
190
|
+
switch (esmx.command) {
|
|
191
|
+
case esmx.COMMAND.dev:
|
|
192
|
+
app.middleware = mergeMiddlewares([
|
|
193
|
+
...(await createMiddleware(esmx, options)),
|
|
194
|
+
app.middleware
|
|
195
|
+
]);
|
|
196
|
+
app.render = rewriteRender(esmx);
|
|
197
|
+
break;
|
|
198
|
+
case esmx.COMMAND.build:
|
|
199
|
+
app.build = rewriteBuild(esmx, options);
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
return app;
|
|
203
|
+
}
|
|
204
|
+
async function createMiddleware(
|
|
205
|
+
esmx: Esmx,
|
|
206
|
+
options: RspackAppOptions = {}
|
|
207
|
+
): Promise<Middleware[]> {
|
|
208
|
+
if (esmx.command !== esmx.COMMAND.dev) {
|
|
209
|
+
return [];
|
|
210
|
+
}
|
|
211
|
+
// const middlewares: Middleware[] = [];
|
|
212
|
+
|
|
213
|
+
const rsBuild = createRsBuild([
|
|
214
|
+
generateBuildConfig(esmx, options, 'client'),
|
|
215
|
+
generateBuildConfig(esmx, options, 'server')
|
|
216
|
+
]);
|
|
217
|
+
rsBuild.watch();
|
|
218
|
+
|
|
219
|
+
// @ts-ignore
|
|
220
|
+
const hot = hotMiddleware(rsBuild.compilers[0], {
|
|
221
|
+
path: `${esmx.basePath}hot-middleware`
|
|
222
|
+
});
|
|
223
|
+
return [
|
|
224
|
+
(req, res, next) => {
|
|
225
|
+
if (req.url?.startsWith(`${esmx.basePath}hot-middleware`)) {
|
|
226
|
+
// @ts-ignore
|
|
227
|
+
return hot(req, res, next);
|
|
228
|
+
}
|
|
229
|
+
return next();
|
|
230
|
+
}
|
|
231
|
+
];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function generateBuildConfig(
|
|
235
|
+
esmx: Esmx,
|
|
236
|
+
options: RspackAppOptions,
|
|
237
|
+
buildTarget: BuildTarget
|
|
238
|
+
) {
|
|
239
|
+
const config = createRspackConfig(esmx, buildTarget, options);
|
|
240
|
+
options.config?.({ esmx, options, buildTarget, config });
|
|
241
|
+
|
|
242
|
+
return config;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function rewriteRender(esmx: Esmx) {
|
|
246
|
+
return async (options?: RenderContextOptions): Promise<RenderContext> => {
|
|
247
|
+
const baseURL = pathToFileURL(esmx.root);
|
|
248
|
+
const importMap = await esmx.getImportMap('server');
|
|
249
|
+
const vmImport = createVmImport(baseURL, importMap);
|
|
250
|
+
const rc = new RenderContext(esmx, options);
|
|
251
|
+
const module = await vmImport(
|
|
252
|
+
`${esmx.name}/src/entry.server`,
|
|
253
|
+
import.meta.url,
|
|
254
|
+
{
|
|
255
|
+
console,
|
|
256
|
+
setTimeout,
|
|
257
|
+
clearTimeout,
|
|
258
|
+
process,
|
|
259
|
+
URL,
|
|
260
|
+
global
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
const serverRender: ServerRenderHandle = module[rc.entryName];
|
|
264
|
+
if (typeof serverRender === 'function') {
|
|
265
|
+
await serverRender(rc);
|
|
266
|
+
}
|
|
267
|
+
return rc;
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function rewriteBuild(esmx: Esmx, options: RspackAppOptions = {}) {
|
|
272
|
+
return async (): Promise<boolean> => {
|
|
273
|
+
for (const item of esmx.moduleConfig.exports) {
|
|
274
|
+
if (item.type === PathType.root) {
|
|
275
|
+
const text = fs.readFileSync(
|
|
276
|
+
esmx.resolvePath('./', item.exportPath),
|
|
277
|
+
'utf-8'
|
|
278
|
+
);
|
|
279
|
+
if (/\bexport\s+\*\s+from\b/.test(text)) {
|
|
280
|
+
console.log(
|
|
281
|
+
styleText(
|
|
282
|
+
'red',
|
|
283
|
+
`The export * syntax is used in the file '${item.exportPath}', which will cause the packaging to fail.`
|
|
284
|
+
)
|
|
285
|
+
);
|
|
286
|
+
console.log(
|
|
287
|
+
styleText(
|
|
288
|
+
'red',
|
|
289
|
+
`Please use specific export syntax, such as export { a, b } from './a';`
|
|
290
|
+
)
|
|
291
|
+
);
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
await createRsBuild([
|
|
297
|
+
generateBuildConfig(esmx, options, 'client'),
|
|
298
|
+
generateBuildConfig(esmx, options, 'server'),
|
|
299
|
+
generateBuildConfig(esmx, options, 'node')
|
|
300
|
+
]).build();
|
|
301
|
+
esmx.writeSync(
|
|
302
|
+
esmx.resolvePath('dist/index.js'),
|
|
303
|
+
`
|
|
304
|
+
async function start() {
|
|
305
|
+
const options = await import('./node/src/entry.node.js').then(
|
|
306
|
+
(mod) => mod.default
|
|
307
|
+
);
|
|
308
|
+
const { Esmx } = await import('@esmx/core');
|
|
309
|
+
const esmx = new Esmx(options);
|
|
310
|
+
|
|
311
|
+
await esmx.init(esmx.COMMAND.start);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
start();
|
|
315
|
+
`.trim()
|
|
316
|
+
);
|
|
317
|
+
return pack(esmx);
|
|
318
|
+
};
|
|
319
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import type { Esmx } from '@esmx/core';
|
|
2
|
+
import { moduleLinkPlugin } from '@esmx/rspack-module-link-plugin';
|
|
3
|
+
import {
|
|
4
|
+
type ExternalItem,
|
|
5
|
+
type Plugins,
|
|
6
|
+
type RspackOptions,
|
|
7
|
+
rspack
|
|
8
|
+
} from '@rspack/core';
|
|
9
|
+
import nodeExternals from 'webpack-node-externals';
|
|
10
|
+
import type { RspackAppOptions } from './app';
|
|
11
|
+
import type { BuildTarget } from './build-target';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 构建 Client、Server、Node 的基础配置
|
|
15
|
+
*/
|
|
16
|
+
export function createRspackConfig(
|
|
17
|
+
esmx: Esmx,
|
|
18
|
+
buildTarget: BuildTarget,
|
|
19
|
+
options: RspackAppOptions
|
|
20
|
+
): RspackOptions {
|
|
21
|
+
const isWebApp = buildTarget === 'client' || buildTarget === 'server';
|
|
22
|
+
const isHot = buildTarget === 'client' && !esmx.isProd;
|
|
23
|
+
return {
|
|
24
|
+
/**
|
|
25
|
+
* 项目根目录,不可修改
|
|
26
|
+
*/
|
|
27
|
+
context: esmx.root,
|
|
28
|
+
entry: (() => {
|
|
29
|
+
const importPaths: string[] = [];
|
|
30
|
+
switch (buildTarget) {
|
|
31
|
+
case 'client':
|
|
32
|
+
importPaths.push(esmx.resolvePath('src/entry.client.ts'));
|
|
33
|
+
isHot &&
|
|
34
|
+
importPaths.push(
|
|
35
|
+
`${resolve('webpack-hot-middleware/client')}?path=${esmx.basePath}hot-middleware&timeout=5000&overlay=false`
|
|
36
|
+
);
|
|
37
|
+
break;
|
|
38
|
+
case 'server':
|
|
39
|
+
importPaths.push(esmx.resolvePath('src/entry.server.ts'));
|
|
40
|
+
break;
|
|
41
|
+
case 'node':
|
|
42
|
+
importPaths.push(esmx.resolvePath('src/entry.node.ts'));
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
[`./src/entry.${buildTarget}`]: {
|
|
47
|
+
import: importPaths
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
})(),
|
|
51
|
+
output: {
|
|
52
|
+
clean: esmx.isProd,
|
|
53
|
+
module: true,
|
|
54
|
+
chunkFormat: esmx.isProd ? 'module' : undefined,
|
|
55
|
+
chunkLoading: esmx.isProd ? 'import' : undefined,
|
|
56
|
+
chunkFilename: esmx.isProd
|
|
57
|
+
? 'chunks/[name].[contenthash:8].final.js'
|
|
58
|
+
: 'chunks/[name].js',
|
|
59
|
+
library: {
|
|
60
|
+
type: esmx.isProd ? 'modern-module' : 'module'
|
|
61
|
+
},
|
|
62
|
+
filename:
|
|
63
|
+
buildTarget !== 'node' && esmx.isProd
|
|
64
|
+
? '[name].[contenthash:8].final.js'
|
|
65
|
+
: '[name].js',
|
|
66
|
+
cssFilename: esmx.isProd
|
|
67
|
+
? '[name].[contenthash:8].final.css'
|
|
68
|
+
: '[name].css',
|
|
69
|
+
cssChunkFilename: esmx.isProd
|
|
70
|
+
? 'chunks/[name].[contenthash:8].final.css'
|
|
71
|
+
: 'chunks/[name].css',
|
|
72
|
+
publicPath:
|
|
73
|
+
buildTarget === 'client'
|
|
74
|
+
? 'auto'
|
|
75
|
+
: `${esmx.basePathPlaceholder}${esmx.basePath}`,
|
|
76
|
+
uniqueName: esmx.varName,
|
|
77
|
+
hotUpdateChunkFilename: '__hot__/[id].[fullhash].hot-update.js',
|
|
78
|
+
hotUpdateMainFilename:
|
|
79
|
+
'__hot__/[runtime].[fullhash].hot-update.json',
|
|
80
|
+
path: ((): string => {
|
|
81
|
+
switch (buildTarget) {
|
|
82
|
+
case 'client':
|
|
83
|
+
return esmx.resolvePath('dist/client');
|
|
84
|
+
case 'server':
|
|
85
|
+
return esmx.resolvePath('dist/server');
|
|
86
|
+
case 'node':
|
|
87
|
+
return esmx.resolvePath('dist/node');
|
|
88
|
+
}
|
|
89
|
+
})(),
|
|
90
|
+
environment: {
|
|
91
|
+
nodePrefixForCoreModules: true
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
// 默认插件,不可修改
|
|
95
|
+
plugins: ((): Plugins => {
|
|
96
|
+
return [
|
|
97
|
+
// 进度条插件
|
|
98
|
+
new rspack.ProgressPlugin({
|
|
99
|
+
prefix: buildTarget
|
|
100
|
+
}),
|
|
101
|
+
// 模块链接插件
|
|
102
|
+
isWebApp ? moduleLinkPlugin(esmx.moduleConfig) : false,
|
|
103
|
+
// 热更新插件
|
|
104
|
+
isHot ? new rspack.HotModuleReplacementPlugin() : false
|
|
105
|
+
];
|
|
106
|
+
})(),
|
|
107
|
+
module: {
|
|
108
|
+
parser: {
|
|
109
|
+
javascript: {
|
|
110
|
+
url: buildTarget === 'client' ? true : 'relative',
|
|
111
|
+
importMeta: false,
|
|
112
|
+
strictExportPresence: true
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
generator: {
|
|
116
|
+
asset: {
|
|
117
|
+
emit: buildTarget === 'client'
|
|
118
|
+
},
|
|
119
|
+
'asset/resource': {
|
|
120
|
+
emit: buildTarget === 'client'
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
rules: []
|
|
124
|
+
},
|
|
125
|
+
resolve: {
|
|
126
|
+
alias: {
|
|
127
|
+
[esmx.name]: esmx.root
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
optimization: {
|
|
131
|
+
minimize: options.minimize ?? esmx.isProd,
|
|
132
|
+
avoidEntryIife: esmx.isProd,
|
|
133
|
+
concatenateModules: esmx.isProd,
|
|
134
|
+
emitOnErrors: true,
|
|
135
|
+
splitChunks: {
|
|
136
|
+
chunks: 'async'
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
externalsPresets: {
|
|
140
|
+
web: buildTarget === 'client',
|
|
141
|
+
node: buildTarget === 'server' || buildTarget === 'node'
|
|
142
|
+
},
|
|
143
|
+
externalsType: 'module-import',
|
|
144
|
+
externals: ((): ExternalItem[] => {
|
|
145
|
+
if (buildTarget === 'node') {
|
|
146
|
+
return [
|
|
147
|
+
// @ts-ignore
|
|
148
|
+
nodeExternals({
|
|
149
|
+
// @ts-ignore
|
|
150
|
+
importType: 'module-import'
|
|
151
|
+
})
|
|
152
|
+
];
|
|
153
|
+
}
|
|
154
|
+
return [];
|
|
155
|
+
})(),
|
|
156
|
+
experiments: {
|
|
157
|
+
outputModule: true,
|
|
158
|
+
parallelCodeSplitting: true,
|
|
159
|
+
rspackFuture: {
|
|
160
|
+
bundlerInfo: { force: false }
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
target: buildTarget === 'client' ? 'web' : 'node22.6',
|
|
164
|
+
mode: esmx.isProd ? 'production' : 'development',
|
|
165
|
+
cache: !esmx.isProd
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function resolve(name: string) {
|
|
170
|
+
return new URL(import.meta.resolve(name)).pathname;
|
|
171
|
+
}
|