Skip to content

Commit 987716a

Browse files
authored
fix(enhanced): correct the condition for provideExternalRuntime field (#4478)
1 parent e1970eb commit 987716a

File tree

5 files changed

+77
-59
lines changed

5 files changed

+77
-59
lines changed

.changeset/breezy-seals-brake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@module-federation/enhanced': patch
3+
---
4+
5+
fix(enhanced): correct the condition for provideExternalRuntime field

apps/website-new/docs/en/configure/experiments.mdx

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,6 @@
22

33
The `experiments` configuration enables advanced and experimental capabilities in the plugin.
44

5-
- Example
6-
7-
```ts
8-
new ModuleFederationPlugin({
9-
name: '@demo/host',
10-
experiments: {
11-
asyncStartup: true,
12-
externalRuntime: false,
13-
provideExternalRuntime: false,
14-
optimization: {
15-
disableSnapshot: false,
16-
target: 'web',
17-
},
18-
},
19-
shared: {
20-
react: {
21-
singleton: true,
22-
},
23-
'react-dom': {
24-
singleton: true,
25-
},
26-
},
27-
//...
28-
});
29-
```
30-
315
## asyncStartup
326

337
- **Type:** `boolean`
@@ -50,7 +24,7 @@ When using this mode, all entrypoints will initialize asynchronously. If you're
5024
- **Required:** No
5125
- **Default:** `false`
5226

53-
After setting `true`, the external MF runtime will be used and the runtime provided by the consumer will be used. (Please make sure your consumer has `provideExternalRuntime: true` set, otherwise it will not run properly!)
27+
After setting `true`, the external {props.name || 'Module Federation'} runtime will be used and the runtime provided by the consumer will be used. (Please make sure your consumer has `provideExternalRuntime: true` set, otherwise it will not run properly!)
5428

5529
## provideExternalRuntime
5630

@@ -62,7 +36,7 @@ After setting `true`, the external MF runtime will be used and the runtime provi
6236
Make sure to only configure it on the topmost consumer! If multiple consumers inject runtime at the same time, the ones executed later will not overwrite the existing runtime.
6337
:::
6438

65-
Setting `true` will inject the MF runtime at the consumer.
39+
Setting `true` will inject the {props.name || 'Module Federation'} runtime at the consumer.
6640

6741
## optimization
6842

apps/website-new/docs/zh/configure/experiments.mdx

Lines changed: 62 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,6 @@
22

33
`experiments` 配置用于启用插件中的实验功能。
44

5-
- Example
6-
7-
```ts
8-
new ModuleFederationPlugin({
9-
name: '@demo/host',
10-
experiments: {
11-
asyncStartup: true,
12-
externalRuntime: false,
13-
provideExternalRuntime: false
14-
},
15-
shared: {
16-
react: {
17-
singleton: true,
18-
},
19-
'react-dom': {
20-
singleton: true,
21-
},
22-
},
23-
//...
24-
});
25-
```
26-
275
## asyncStartup
286

297
- Type: `boolean`
@@ -46,7 +24,7 @@ new ModuleFederationPlugin({
4624
- Required: No
4725
- Default: `false`
4826

49-
设置 `true` 后 会 external MF runtime,并使用消费者提供的 runtime 。(请确保你的消费者有设置 `provideExternalRuntime: true`,否则无法正常运行!)
27+
设置 `true` 后 会 external {props.name || 'Module Federation'} runtime,并使用消费者提供的 runtime 。(请确保你的消费者有设置 `provideExternalRuntime: true`,否则无法正常运行!)
5028

5129
## provideExternalRuntime
5230

@@ -58,4 +36,64 @@ new ModuleFederationPlugin({
5836
请确保仅在最顶层消费者配置!若同时有多个消费者注入 runtime,后执行的不会覆盖已有的 runtime。
5937
:::
6038

61-
设置 `true` 后会在消费者处注入 MF runtime。
39+
设置 `true` 后会在消费者处注入 {props.name || 'Module Federation'} runtime。
40+
41+
42+
## optimization
43+
44+
该对象包含与构建期优化相关的标记,这些标记会影响 Module Federation 运行时的体积与行为。
45+
46+
### disableSnapshot
47+
48+
- **Type:** `boolean`
49+
- **Required:** No
50+
- **Default:** `false`
51+
52+
当设置为 `true` 时,该选项会在构建期间将全局常量 `FEDERATION_OPTIMIZE_NO_SNAPSHOT_PLUGIN` 定义为 `true`。在 `@module-federation/runtime-core` 中,这会阻止 `snapshotPlugin()``generatePreloadAssetsPlugin()` 被打包并在 Module Federation 实例中初始化。
53+
54+
**影响:**
55+
* **收益:** 排除这两个插件的代码后,可减小 {props.name || 'Module Federation'} 运行时的整体包体积。
56+
* **代价:** 会禁用这两个插件提供的能力。`snapshotPlugin` 对 “mf-manifest 协议” 非常关键,它负责生成或在运行时提供构建清单(例如 `mf-manifest.json`)的访问能力,清单中包含暴露模块、共享依赖、版本与远程模块等元数据。禁用后意味着:
57+
* 运行时将无法访问这份构建清单数据。
58+
* 依赖清单的能力(如动态远程发现、基于清单的版本兼容检查、高级资源预加载(也由被移除的 `generatePreloadAssetsPlugin` 处理)以及可能的运行时调试/自省工具)将无法正常工作或不可用。
59+
* 仅当你不依赖这些由清单驱动的能力,并且更优先考虑最小化运行时体积时,才建议开启此选项。
60+
61+
:::warning
62+
**注意:** 设置 `disableSnapshot: true` 会禁用 manifest 协议。这意味着你将失去联邦模块的 TypeScript 同步支持与热更新(HMR)能力。如果你只使用 `.js` 类型的远程模块(非基于 manifest 的远程模块),则不会损失功能,因为 `.js` 远程本身不支持这些能力。
63+
:::
64+
65+
### target
66+
67+
- **Type:** `'web' | 'node'`
68+
- **Required:** No
69+
- **Default:** Inferred from Webpack's `target` option (usually `'web'`)
70+
71+
该选项会在构建期间定义全局常量 `ENV_TARGET`,用于指定目标运行环境。
72+
73+
**影响:**
74+
* **`target: 'web'`**:针对浏览器环境优化构建。
75+
* 确保使用浏览器端的远程入口加载机制(`loadEntryDom`)。
76+
* 关键点在于会对 `@module-federation/sdk` 中 Node.js 专属代码启用 tree-shaking/死代码消除。`createScriptNode``loadScriptNode` 等函数及其依赖的 Node.js 内置模块(如 `vm``path``http`)会被完全移出产物,从而显著减小包体积。
77+
* **`target: 'node'`**:针对 Node.js 环境优化构建。
78+
* 确保使用 Node.js 端的远程入口加载机制(`loadEntryNode`)。
79+
* 会把 SDK 中 Node.js 场景所需的函数(`createScriptNode``loadScriptNode`)保留在产物中,保证联邦应用在 Node.js 中正常运行。
80+
81+
建议显式设置该值,以确保应用预期优化,尤其是在同构或服务端渲染场景中。
82+
83+
### 优化标记对 `remoteEntry.js` 体积的影响
84+
85+
下表展示了 `disableSnapshot``target: 'web'``externalRuntime` 这几个优化标记在不同组合下,对生成的 `remoteEntry.js` 文件体积的影响。这些数据可帮助你在运行时功能与包体积之间做出取舍。
86+
87+
| 优化标记组合 | remoteEntry.js | Gzip Size | Brotli Size |
88+
|--------------------------------------------|:--------------:|:---------:|:-----------:|
89+
| 未启用任何优化标记 | 69K | 21437 B | 19024 B |
90+
| `disableSnapshot: true` | 65K | 20096 B | 17860 B |
91+
| `target: 'web'` | 60K | 19314 B | 17105 B |
92+
| 两者同时启用 | 56K | 17998 B | 15982 B |
93+
| 两者启用 + `externalRuntime: true` | 14K | 5381 B | 4703 B |
94+
| 两者关闭 + `externalRuntime: true` | 22K | 8222 B | 7269 B |
95+
96+
**说明:**
97+
- 同时开启 `disableSnapshot``target: 'web'` 可获得更明显的体积下降,配合 `externalRuntime: true` 时效果最佳。
98+
- 使用外部运行时(`externalRuntime: true`)可大幅缩小 remote entry 体积,但前提是消费者侧提供运行时。
99+
- 更小的包体积通常意味着更快的加载速度与更好的性能,但也可能禁用部分能力(各标记行为见上文)。

apps/website-new/module-federation.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const exposes = {
4242
[`./configure-tree-shaking-shared-exclude-plugins-${LANGUAGE}`]: `./docs/${LANGUAGE}/configure/treeShakingSharedExcludePlugins.mdx`,
4343
[`./configure-tree-shaking-shared-plugins-${LANGUAGE}`]: `./docs/${LANGUAGE}/configure/treeShakingSharedPlugins.mdx`,
4444
[`./configure-inject-tree-shaking-used-exports-${LANGUAGE}`]: `./docs/${LANGUAGE}/configure/injectTreeShakingUsedExports.mdx`,
45+
[`./configure-experiments-${LANGUAGE}`]: `./docs/${LANGUAGE}/configure/experiments.mdx`,
4546

4647
// [`./configure-shareStrategy-${LANGUAGE}`]: `./docs/${LANGUAGE}/configure/shareStrategy.mdx`,
4748
// [`./configure-experiments-${LANGUAGE}`]: `./docs/${LANGUAGE}/configure/experiments.mdx`,

packages/enhanced/src/lib/container/ModuleFederationPlugin.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,14 @@ class ModuleFederationPlugin implements WebpackPluginInstance {
118118
(new RemoteEntryPlugin(options) as unknown as WebpackPluginInstance).apply(
119119
compiler,
120120
);
121+
const useContainerPlugin =
122+
options.exposes &&
123+
(Array.isArray(options.exposes)
124+
? options.exposes.length > 0
125+
: Object.keys(options.exposes).length > 0);
126+
121127
if (experiments?.provideExternalRuntime) {
122-
if (options.exposes) {
128+
if (useContainerPlugin) {
123129
throw new Error(
124130
'You can only set provideExternalRuntime: true in pure consumer which not expose modules.',
125131
);
@@ -169,12 +175,6 @@ class ModuleFederationPlugin implements WebpackPluginInstance {
169175
const containerRemoteType =
170176
remoteType as moduleFederationPlugin.ExternalsType;
171177

172-
const useContainerPlugin =
173-
options.exposes &&
174-
(Array.isArray(options.exposes)
175-
? options.exposes.length > 0
176-
: Object.keys(options.exposes).length > 0);
177-
178178
let disableManifest = options.manifest === false;
179179
if (useContainerPlugin) {
180180
ContainerPlugin.patchChunkSplit(compiler, name);

0 commit comments

Comments
 (0)