@lark-apaas/fullstack-rspack-preset 1.0.55-alpha.20 → 1.0.55-alpha.22

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/lib/preset.js CHANGED
@@ -196,6 +196,7 @@ function createRecommendRspackConfig(options) {
196
196
  new runtime_injection_plugin_1.default(),
197
197
  // basename 运行时注入 - 改写入口文件 process.env.CLIENT_BASE_PATH 为运行时读 window.__BASENAME__
198
198
  // 必须在 DefinePlugin 之前生效(plugin 内部 enforce:'pre')
199
+ // 匹配 client/src/ 根层级入口文件(index.tsx / main.tsx 等),不影响 SDK 内部代码
199
200
  new basename_injection_plugin_1.default({ envBasePath: clientBasePath }),
200
201
  new core_1.default.BannerPlugin({
201
202
  banner: `window.__RELEASE_COMMIT_ID__ = '${releaseId}';`,
@@ -1,13 +1,17 @@
1
1
  /**
2
2
  * Basename Injection Plugin for Rspack
3
3
  *
4
- * 在 module rules 最前面注入一个 loader,仅匹配应用入口文件
5
- * (client/src/index.{ts,tsx,js,jsx}),把入口里的 process.env.CLIENT_BASE_PATH
4
+ * 在 module rules 最前面注入一个 loader,仅匹配应用入口文件,
5
+ * 把入口里的 process.env.CLIENT_BASE_PATH
6
6
  * 改写为运行时读 window.__BASENAME__(fallback 到构建时常量)。
7
7
  *
8
8
  * 让 BrowserRouter basename 运行时动态化,实现同一份 bundle 跑在不同 basename 下
9
9
  * (默认域名 `/app/<appId>`、自定义域名 `/` 或 `/<alias>`)。
10
10
  *
11
+ * 入口文件识别:在 entryOption hook(配置已完全解析合并)中从 entry 提取业务入口路径,
12
+ * 过滤掉 node_modules 包名(runtime 注入、polyfill 等非业务入口)和 Module Federation
13
+ * 远程模块,生成精确匹配正则。兜底到 client/src/index.{tsx,ts,jsx,js} 正则。
14
+ *
11
15
  * 关键约束:
12
16
  * - 只匹配入口文件,不影响 SDK 内部代码(如 client-toolkit-lite 仍读编译期常量)
13
17
  * - loader 阶段天然早于 DefinePlugin 的表达式替换(rspack 内部 source-transform → parsing → DefinePlugin 流水线顺序)
@@ -2,13 +2,17 @@
2
2
  /**
3
3
  * Basename Injection Plugin for Rspack
4
4
  *
5
- * 在 module rules 最前面注入一个 loader,仅匹配应用入口文件
6
- * (client/src/index.{ts,tsx,js,jsx}),把入口里的 process.env.CLIENT_BASE_PATH
5
+ * 在 module rules 最前面注入一个 loader,仅匹配应用入口文件,
6
+ * 把入口里的 process.env.CLIENT_BASE_PATH
7
7
  * 改写为运行时读 window.__BASENAME__(fallback 到构建时常量)。
8
8
  *
9
9
  * 让 BrowserRouter basename 运行时动态化,实现同一份 bundle 跑在不同 basename 下
10
10
  * (默认域名 `/app/<appId>`、自定义域名 `/` 或 `/<alias>`)。
11
11
  *
12
+ * 入口文件识别:在 entryOption hook(配置已完全解析合并)中从 entry 提取业务入口路径,
13
+ * 过滤掉 node_modules 包名(runtime 注入、polyfill 等非业务入口)和 Module Federation
14
+ * 远程模块,生成精确匹配正则。兜底到 client/src/index.{tsx,ts,jsx,js} 正则。
15
+ *
12
16
  * 关键约束:
13
17
  * - 只匹配入口文件,不影响 SDK 内部代码(如 client-toolkit-lite 仍读编译期常量)
14
18
  * - loader 阶段天然早于 DefinePlugin 的表达式替换(rspack 内部 source-transform → parsing → DefinePlugin 流水线顺序)
@@ -22,7 +26,50 @@ Object.defineProperty(exports, "__esModule", { value: true });
22
26
  exports.BasenameInjectionPlugin = void 0;
23
27
  const path_1 = __importDefault(require("path"));
24
28
  const PLUGIN_NAME = 'BasenameInjectionPlugin';
25
- const ENTRY_FILE_REGEX = /[/\\]client[/\\]src[/\\]index\.(tsx?|jsx?)$/;
29
+ const FALLBACK_ENTRY_REGEX = /[/\\]client[/\\]src[/\\]index\.(tsx?|jsx?)$/;
30
+ /**
31
+ * 判断 import 路径是否为本地业务文件(相对路径或绝对路径),
32
+ * 排除 node_modules 包名(runtime 注入、polyfill、HMR client 等)。
33
+ */
34
+ function isLocalFile(imp) {
35
+ return imp.startsWith('.') || imp.startsWith('/');
36
+ }
37
+ /**
38
+ * 从 entry 配置中提取所有本地业务入口文件的绝对路径。
39
+ *
40
+ * entry 结构(entryOption hook 阶段已规范化):
41
+ * { main: { import: ['@lark-apaas/client-toolkit/runtime', './client/src/index.tsx'] } }
42
+ *
43
+ * 过滤规则:
44
+ * - 跳过非本地路径(node_modules 包名,如 runtime 注入、polyfill、HMR client)
45
+ * - 跳过 node_modules 内的文件(Module Federation 远程模块等)
46
+ */
47
+ function resolveEntryFiles(entry, context) {
48
+ const files = [];
49
+ for (const descriptor of Object.values(entry)) {
50
+ const imports = descriptor.import;
51
+ if (!Array.isArray(imports))
52
+ continue;
53
+ for (const imp of imports) {
54
+ if (!isLocalFile(imp))
55
+ continue;
56
+ const resolved = path_1.default.resolve(context, imp);
57
+ if (resolved.includes('node_modules'))
58
+ continue;
59
+ files.push(resolved);
60
+ }
61
+ }
62
+ return files;
63
+ }
64
+ /**
65
+ * 构建入口文件匹配正则:精确匹配 resolved 路径,无路径时兜底默认正则。
66
+ */
67
+ function buildEntryTest(entryFiles) {
68
+ if (entryFiles.length === 0)
69
+ return FALLBACK_ENTRY_REGEX;
70
+ const escaped = entryFiles.map(f => path_1.default.normalize(f).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
71
+ return new RegExp(`(${escaped.join('|')})$`);
72
+ }
26
73
  class BasenameInjectionPlugin {
27
74
  constructor(options = {}) {
28
75
  this.envBasePath = options.envBasePath ?? process.env.CLIENT_BASE_PATH ?? '';
@@ -30,15 +77,22 @@ class BasenameInjectionPlugin {
30
77
  apply(compiler) {
31
78
  const loaderPath = path_1.default.resolve(__dirname, './basename-injection-loader.js');
32
79
  const envBasePath = this.envBasePath;
33
- compiler.hooks.afterEnvironment.tap(PLUGIN_NAME, () => {
80
+ // entryOption hook:配置已完全解析合并(包括异步 entry 函数的返回值),
81
+ // 是读 entry 最安全的时机。参考 RuntimeInjectionPlugin 的做法。
82
+ compiler.hooks.entryOption.tap(PLUGIN_NAME, (_context, entry) => {
83
+ const context = compiler.options.context || process.cwd();
84
+ // 动态 entry(函数形式)无法在此阶段解析,兜底到默认正则
85
+ const entryFiles = (typeof entry !== 'function')
86
+ ? resolveEntryFiles(entry, context)
87
+ : [];
88
+ const entryTest = buildEntryTest(entryFiles);
34
89
  if (!compiler.options.module) {
35
- // 极端兜底:rspack 必定提供 module,这里只是 narrow type
36
90
  compiler.options.module = { rules: [] };
37
91
  }
38
92
  const rules = compiler.options.module.rules || [];
39
93
  compiler.options.module.rules = [
40
94
  {
41
- test: ENTRY_FILE_REGEX,
95
+ test: entryTest,
42
96
  enforce: 'pre',
43
97
  use: [
44
98
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/fullstack-rspack-preset",
3
- "version": "1.0.55-alpha.20",
3
+ "version": "1.0.55-alpha.22",
4
4
  "files": [
5
5
  "lib",
6
6
  "patches",