@module-federation/rsbuild-plugin 2.0.1 → 2.2.0
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 +47 -0
- package/dist/cli/index.js +64 -14
- package/dist/cli/index.mjs +65 -15
- package/dist/utils/ssr.d.ts +0 -1
- package/dist/utils/ssr.js +35 -12
- package/dist/utils/ssr.mjs +35 -12
- package/package.json +11 -5
package/README.md
CHANGED
|
@@ -34,6 +34,53 @@ export default defineConfig({
|
|
|
34
34
|
});
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
### Rsbuild App SSR (Node target with custom environment)
|
|
38
|
+
|
|
39
|
+
Use `target: 'node'` with an explicit `environment` to apply federation to a
|
|
40
|
+
specific Rsbuild app environment (for example `ssr`).
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { pluginModuleFederation } from '@module-federation/rsbuild-plugin';
|
|
44
|
+
import { defineConfig } from '@rsbuild/core';
|
|
45
|
+
|
|
46
|
+
export default defineConfig({
|
|
47
|
+
environments: {
|
|
48
|
+
client: {},
|
|
49
|
+
ssr: {},
|
|
50
|
+
},
|
|
51
|
+
plugins: [
|
|
52
|
+
pluginModuleFederation(
|
|
53
|
+
{
|
|
54
|
+
name: 'host',
|
|
55
|
+
remotes: {
|
|
56
|
+
remote: 'remote@http://localhost:3001/mf-manifest.json',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
target: 'node',
|
|
61
|
+
environment: 'ssr',
|
|
62
|
+
},
|
|
63
|
+
),
|
|
64
|
+
],
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`target: 'dual'` support remains scoped to Rslib/Rspress workflows.
|
|
69
|
+
|
|
70
|
+
### Default environment detection
|
|
71
|
+
|
|
72
|
+
If `environment` is omitted, the plugin will choose a default per tool:
|
|
73
|
+
|
|
74
|
+
- **Rslib**: `mf`
|
|
75
|
+
- **Rsbuild app**:
|
|
76
|
+
- `target: 'web'` → `web`
|
|
77
|
+
- `target: 'node'` → `node`
|
|
78
|
+
- **Rspress**:
|
|
79
|
+
- `target: 'web'` → `web`
|
|
80
|
+
- `target: 'node'` → `node`
|
|
81
|
+
|
|
82
|
+
You can still override with `environment` when your project uses custom names.
|
|
83
|
+
|
|
37
84
|
### Rslib Module
|
|
38
85
|
|
|
39
86
|
```js
|
package/dist/cli/index.js
CHANGED
|
@@ -97,6 +97,23 @@ const LIB_FORMAT = [
|
|
|
97
97
|
'modern-module'
|
|
98
98
|
];
|
|
99
99
|
const DEFAULT_MF_ENVIRONMENT_NAME = 'mf';
|
|
100
|
+
const DEFAULT_WEB_ENVIRONMENT_NAME = 'web';
|
|
101
|
+
const DEFAULT_NODE_ENVIRONMENT_NAME = 'node';
|
|
102
|
+
const resolveDefaultEnvironmentName = ({ callerName, target })=>{
|
|
103
|
+
if (callerName === external_constant_js_namespaceObject.CALL_NAME_MAP.RSLIB) {
|
|
104
|
+
return DEFAULT_MF_ENVIRONMENT_NAME;
|
|
105
|
+
}
|
|
106
|
+
if (callerName === external_constant_js_namespaceObject.CALL_NAME_MAP.RSPRESS) {
|
|
107
|
+
if (target === 'node') {
|
|
108
|
+
return DEFAULT_NODE_ENVIRONMENT_NAME;
|
|
109
|
+
}
|
|
110
|
+
return DEFAULT_WEB_ENVIRONMENT_NAME;
|
|
111
|
+
}
|
|
112
|
+
if (target === 'node') {
|
|
113
|
+
return DEFAULT_NODE_ENVIRONMENT_NAME;
|
|
114
|
+
}
|
|
115
|
+
return DEFAULT_WEB_ENVIRONMENT_NAME;
|
|
116
|
+
};
|
|
100
117
|
function isStoryBook(rsbuildConfig) {
|
|
101
118
|
var _rsbuildConfig_plugins;
|
|
102
119
|
if ((_rsbuildConfig_plugins = rsbuildConfig.plugins) === null || _rsbuildConfig_plugins === void 0 ? void 0 : _rsbuildConfig_plugins.find((p)=>p && 'name' in p && p.name === 'module-federation-storybook-plugin')) {
|
|
@@ -123,7 +140,10 @@ const isRspressSSGConfig = (bundlerConfigName)=>{
|
|
|
123
140
|
const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
124
141
|
name: RSBUILD_PLUGIN_MODULE_FEDERATION_NAME,
|
|
125
142
|
setup: (api)=>{
|
|
126
|
-
|
|
143
|
+
if (!(moduleFederationOptions === null || moduleFederationOptions === void 0 ? void 0 : moduleFederationOptions.name)) {
|
|
144
|
+
throw new Error('The module federation option "name" is required in @module-federation/rsbuild-plugin.');
|
|
145
|
+
}
|
|
146
|
+
const { target = 'web', ssr = undefined, ssrDir = external_utils_js_namespaceObject.SSR_DIR, environment: configuredEnvironment } = rsbuildOptions || {};
|
|
127
147
|
if (ssr) {
|
|
128
148
|
throw new Error("The `ssr` option is deprecated. If you want to enable SSR, please use `target: 'dual'` instead.");
|
|
129
149
|
}
|
|
@@ -135,6 +155,10 @@ const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
|
135
155
|
const isRslib = callerName === external_constant_js_namespaceObject.CALL_NAME_MAP.RSLIB;
|
|
136
156
|
const isRspress = callerName === external_constant_js_namespaceObject.CALL_NAME_MAP.RSPRESS;
|
|
137
157
|
const isSSR = target === 'dual';
|
|
158
|
+
const environment = configuredEnvironment ?? resolveDefaultEnvironmentName({
|
|
159
|
+
callerName,
|
|
160
|
+
target
|
|
161
|
+
});
|
|
138
162
|
if (isSSR && !isStoryBook(originalRsbuildConfig)) {
|
|
139
163
|
var _rsbuildConfig_environments;
|
|
140
164
|
if (!isRslib && !isRspress) {
|
|
@@ -198,7 +222,11 @@ const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
|
198
222
|
if ((_config_environments = config.environments) === null || _config_environments === void 0 ? void 0 : _config_environments[external_utils_js_namespaceObject.SSR_ENV_NAME]) {
|
|
199
223
|
throw new Error(`'${external_utils_js_namespaceObject.SSR_ENV_NAME}' environment is already defined.Please use another name.`);
|
|
200
224
|
}
|
|
201
|
-
|
|
225
|
+
const currentEnvironment = (_config_environments1 = config.environments) === null || _config_environments1 === void 0 ? void 0 : _config_environments1[environment];
|
|
226
|
+
if (!currentEnvironment) {
|
|
227
|
+
throw new Error(`Can not find environment '${environment}' when enabling SSR.`);
|
|
228
|
+
}
|
|
229
|
+
config.environments[external_utils_js_namespaceObject.SSR_ENV_NAME] = (0,external_utils_js_namespaceObject.createSSRREnvConfig)(currentEnvironment, moduleFederationOptions, ssrDir, config, callerName);
|
|
202
230
|
const ssgMDEnv = config.environments[external_constant_js_namespaceObject.RSPRESS_SSG_MD_ENV_NAME];
|
|
203
231
|
if (isRspress && ssgMDEnv) {
|
|
204
232
|
(0,ssr_js_namespaceObject.patchToolsTspack)(ssgMDEnv, (config, { environment })=>{
|
|
@@ -206,8 +234,14 @@ const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
|
206
234
|
});
|
|
207
235
|
}
|
|
208
236
|
} else if (target === 'node') {
|
|
209
|
-
|
|
210
|
-
(
|
|
237
|
+
var _config_environments2;
|
|
238
|
+
const nodeTargetEnv = (_config_environments2 = config.environments) === null || _config_environments2 === void 0 ? void 0 : _config_environments2[environment];
|
|
239
|
+
if (!nodeTargetEnv) {
|
|
240
|
+
const availableEnvironments = Object.keys(config.environments || {});
|
|
241
|
+
const availableEnvironmentsLabel = availableEnvironments.length > 0 ? availableEnvironments.join(', ') : '(none)';
|
|
242
|
+
throw new Error(`Can not find environment '${environment}' when using target: 'node'. Available environments: ${availableEnvironmentsLabel}.`);
|
|
243
|
+
}
|
|
244
|
+
(0,ssr_js_namespaceObject.patchToolsTspack)(nodeTargetEnv, (config, { environment })=>{
|
|
211
245
|
config.target = 'async-node';
|
|
212
246
|
});
|
|
213
247
|
}
|
|
@@ -284,7 +318,22 @@ const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
|
284
318
|
throw new Error('Can not get bundlerConfigs!');
|
|
285
319
|
}
|
|
286
320
|
bundlerConfigs.forEach((bundlerConfig)=>{
|
|
287
|
-
|
|
321
|
+
const bundlerConfigName = bundlerConfig.name || '';
|
|
322
|
+
const isConfiguredEnvironmentConfig = bundlerConfigName === environment;
|
|
323
|
+
const isNodeTargetEnvironmentConfig = target === 'node' && bundlerConfigName === environment;
|
|
324
|
+
const isRspressSSGEnvironmentConfig = isRspressSSGConfig(bundlerConfig.name);
|
|
325
|
+
const isActiveRspressSSGEnvironmentConfig = isRspress && isRspressSSGEnvironmentConfig;
|
|
326
|
+
const shouldUseSSRPluginConfig = isSSRConfig(bundlerConfig.name) || isNodeTargetEnvironmentConfig;
|
|
327
|
+
if (target === 'node' && !isNodeTargetEnvironmentConfig && !isActiveRspressSSGEnvironmentConfig) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
// For non-node targets, scope each plugin instance to its configured
|
|
331
|
+
// environment plus explicit SSR/SSG environments. This prevents a
|
|
332
|
+
// browser-targeted instance from mutating SSR configs.
|
|
333
|
+
if (target !== 'node' && !isConfiguredEnvironmentConfig && !shouldUseSSRPluginConfig && !isActiveRspressSSGEnvironmentConfig) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (!isMFFormat(bundlerConfig) && !isRspress && !isNodeTargetEnvironmentConfig) {
|
|
288
337
|
return;
|
|
289
338
|
} else if (isStoryBook(originalRsbuildConfig)) {
|
|
290
339
|
bundlerConfig.output.uniqueName = `${moduleFederationOptions.name} -storybook - host`;
|
|
@@ -292,7 +341,8 @@ const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
|
292
341
|
var _bundlerConfig_optimization, _bundlerConfig_optimization1, _bundlerConfig_output, _bundlerConfig_output1, _bundlerConfig_output2;
|
|
293
342
|
// mf
|
|
294
343
|
(0,external_utils_js_namespaceObject.autoDeleteSplitChunkCacheGroups)(moduleFederationOptions, bundlerConfig === null || bundlerConfig === void 0 ? void 0 : (_bundlerConfig_optimization = bundlerConfig.optimization) === null || _bundlerConfig_optimization === void 0 ? void 0 : _bundlerConfig_optimization.splitChunks);
|
|
295
|
-
(0,external_utils_js_namespaceObject.addDataFetchExposes)(moduleFederationOptions.exposes,
|
|
344
|
+
(0,external_utils_js_namespaceObject.addDataFetchExposes)(moduleFederationOptions.exposes, shouldUseSSRPluginConfig);
|
|
345
|
+
const ssrModuleFederationOptions = shouldUseSSRPluginConfig ? (0,external_utils_js_namespaceObject.createSSRMFConfig)(moduleFederationOptions) : undefined;
|
|
296
346
|
(_bundlerConfig_optimization1 = bundlerConfig.optimization) === null || _bundlerConfig_optimization1 === void 0 ? true : delete _bundlerConfig_optimization1.runtimeChunk;
|
|
297
347
|
const externals = bundlerConfig.externals;
|
|
298
348
|
if (Array.isArray(externals)) {
|
|
@@ -334,13 +384,12 @@ const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
|
334
384
|
}
|
|
335
385
|
}
|
|
336
386
|
}
|
|
337
|
-
if (!((_bundlerConfig_output = bundlerConfig.output) === null || _bundlerConfig_output === void 0 ? void 0 : _bundlerConfig_output.chunkLoadingGlobal) && !
|
|
387
|
+
if (!((_bundlerConfig_output = bundlerConfig.output) === null || _bundlerConfig_output === void 0 ? void 0 : _bundlerConfig_output.chunkLoadingGlobal) && !shouldUseSSRPluginConfig && !isActiveRspressSSGEnvironmentConfig && target !== 'node') {
|
|
338
388
|
bundlerConfig.output.chunkLoading = 'jsonp';
|
|
339
389
|
bundlerConfig.output.chunkLoadingGlobal = `chunk_${moduleFederationOptions.name} `;
|
|
340
390
|
}
|
|
341
|
-
if (
|
|
342
|
-
(0,ssr_js_namespaceObject.patchNodeConfig)(bundlerConfig, moduleFederationOptions);
|
|
343
|
-
(0,ssr_js_namespaceObject.patchNodeMFConfig)(moduleFederationOptions);
|
|
391
|
+
if (isNodeTargetEnvironmentConfig) {
|
|
392
|
+
(0,ssr_js_namespaceObject.patchNodeConfig)(bundlerConfig, ssrModuleFederationOptions ?? moduleFederationOptions);
|
|
344
393
|
}
|
|
345
394
|
// `uniqueName` is required for react refresh to work
|
|
346
395
|
if (!((_bundlerConfig_output1 = bundlerConfig.output) === null || _bundlerConfig_output1 === void 0 ? void 0 : _bundlerConfig_output1.uniqueName)) {
|
|
@@ -348,17 +397,18 @@ const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
|
348
397
|
}
|
|
349
398
|
// Set default publicPath to 'auto' if not explicitly configured
|
|
350
399
|
// This allows remote chunks to load from the same origin as the remote application's manifest
|
|
351
|
-
if (((_bundlerConfig_output2 = bundlerConfig.output) === null || _bundlerConfig_output2 === void 0 ? void 0 : _bundlerConfig_output2.publicPath) === undefined && !
|
|
400
|
+
if (((_bundlerConfig_output2 = bundlerConfig.output) === null || _bundlerConfig_output2 === void 0 ? void 0 : _bundlerConfig_output2.publicPath) === undefined && !shouldUseSSRPluginConfig && !isActiveRspressSSGEnvironmentConfig) {
|
|
352
401
|
bundlerConfig.output.publicPath = 'auto';
|
|
353
402
|
}
|
|
354
403
|
if (!bundlerConfig.plugins.find((p)=>p && p.name === rspack_namespaceObject.PLUGIN_NAME)) {
|
|
355
404
|
var _bundlerConfig_output3;
|
|
356
|
-
if (
|
|
357
|
-
|
|
405
|
+
if (shouldUseSSRPluginConfig) {
|
|
406
|
+
const ssrMFConfig = ssrModuleFederationOptions ?? (0,external_utils_js_namespaceObject.createSSRMFConfig)(moduleFederationOptions);
|
|
407
|
+
generateMergedStatsAndManifestOptions.options.nodePlugin = new rspack_namespaceObject.ModuleFederationPlugin(ssrMFConfig);
|
|
358
408
|
generateMergedStatsAndManifestOptions.options.nodeEnvironmentName = bundlerConfig.name || external_utils_js_namespaceObject.SSR_ENV_NAME;
|
|
359
409
|
bundlerConfig.plugins.push(generateMergedStatsAndManifestOptions.options.nodePlugin);
|
|
360
410
|
return;
|
|
361
|
-
} else if (
|
|
411
|
+
} else if (isActiveRspressSSGEnvironmentConfig) {
|
|
362
412
|
const mfConfig = {
|
|
363
413
|
...(0,external_utils_js_namespaceObject.createSSRMFConfig)(moduleFederationOptions),
|
|
364
414
|
// expose in mf-ssg env
|
package/dist/cli/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import package_0 from "../../package.json";
|
|
|
5
5
|
import logger from "../logger.mjs";
|
|
6
6
|
import { SSR_DIR, SSR_ENV_NAME, addDataFetchExposes, autoDeleteSplitChunkCacheGroups, createSSRMFConfig, createSSRREnvConfig, isRegExp, patchSSRRspackConfig, setSSREnv, updateStatsAndManifest } from "../utils.mjs";
|
|
7
7
|
import { CALL_NAME_MAP, RSPRESS_BUNDLER_CONFIG_NAME, RSPRESS_SSG_MD_ENV_NAME, RSPRESS_SSR_DIR } from "../constant.mjs";
|
|
8
|
-
import {
|
|
8
|
+
import { patchNodeConfig, patchToolsTspack } from "../utils/ssr.mjs";
|
|
9
9
|
|
|
10
10
|
;// CONCATENATED MODULE: external "@module-federation/enhanced"
|
|
11
11
|
|
|
@@ -40,6 +40,23 @@ const LIB_FORMAT = [
|
|
|
40
40
|
'modern-module'
|
|
41
41
|
];
|
|
42
42
|
const DEFAULT_MF_ENVIRONMENT_NAME = 'mf';
|
|
43
|
+
const DEFAULT_WEB_ENVIRONMENT_NAME = 'web';
|
|
44
|
+
const DEFAULT_NODE_ENVIRONMENT_NAME = 'node';
|
|
45
|
+
const resolveDefaultEnvironmentName = ({ callerName, target })=>{
|
|
46
|
+
if (callerName === CALL_NAME_MAP.RSLIB) {
|
|
47
|
+
return DEFAULT_MF_ENVIRONMENT_NAME;
|
|
48
|
+
}
|
|
49
|
+
if (callerName === CALL_NAME_MAP.RSPRESS) {
|
|
50
|
+
if (target === 'node') {
|
|
51
|
+
return DEFAULT_NODE_ENVIRONMENT_NAME;
|
|
52
|
+
}
|
|
53
|
+
return DEFAULT_WEB_ENVIRONMENT_NAME;
|
|
54
|
+
}
|
|
55
|
+
if (target === 'node') {
|
|
56
|
+
return DEFAULT_NODE_ENVIRONMENT_NAME;
|
|
57
|
+
}
|
|
58
|
+
return DEFAULT_WEB_ENVIRONMENT_NAME;
|
|
59
|
+
};
|
|
43
60
|
function isStoryBook(rsbuildConfig) {
|
|
44
61
|
var _rsbuildConfig_plugins;
|
|
45
62
|
if ((_rsbuildConfig_plugins = rsbuildConfig.plugins) === null || _rsbuildConfig_plugins === void 0 ? void 0 : _rsbuildConfig_plugins.find((p)=>p && 'name' in p && p.name === 'module-federation-storybook-plugin')) {
|
|
@@ -66,7 +83,10 @@ const isRspressSSGConfig = (bundlerConfigName)=>{
|
|
|
66
83
|
const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
67
84
|
name: RSBUILD_PLUGIN_MODULE_FEDERATION_NAME,
|
|
68
85
|
setup: (api)=>{
|
|
69
|
-
|
|
86
|
+
if (!(moduleFederationOptions === null || moduleFederationOptions === void 0 ? void 0 : moduleFederationOptions.name)) {
|
|
87
|
+
throw new Error('The module federation option "name" is required in @module-federation/rsbuild-plugin.');
|
|
88
|
+
}
|
|
89
|
+
const { target = 'web', ssr = undefined, ssrDir = SSR_DIR, environment: configuredEnvironment } = rsbuildOptions || {};
|
|
70
90
|
if (ssr) {
|
|
71
91
|
throw new Error("The `ssr` option is deprecated. If you want to enable SSR, please use `target: 'dual'` instead.");
|
|
72
92
|
}
|
|
@@ -78,6 +98,10 @@ const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
|
78
98
|
const isRslib = callerName === CALL_NAME_MAP.RSLIB;
|
|
79
99
|
const isRspress = callerName === CALL_NAME_MAP.RSPRESS;
|
|
80
100
|
const isSSR = target === 'dual';
|
|
101
|
+
const environment = configuredEnvironment ?? resolveDefaultEnvironmentName({
|
|
102
|
+
callerName,
|
|
103
|
+
target
|
|
104
|
+
});
|
|
81
105
|
if (isSSR && !isStoryBook(originalRsbuildConfig)) {
|
|
82
106
|
var _rsbuildConfig_environments;
|
|
83
107
|
if (!isRslib && !isRspress) {
|
|
@@ -141,7 +165,11 @@ const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
|
141
165
|
if ((_config_environments = config.environments) === null || _config_environments === void 0 ? void 0 : _config_environments[SSR_ENV_NAME]) {
|
|
142
166
|
throw new Error(`'${SSR_ENV_NAME}' environment is already defined.Please use another name.`);
|
|
143
167
|
}
|
|
144
|
-
|
|
168
|
+
const currentEnvironment = (_config_environments1 = config.environments) === null || _config_environments1 === void 0 ? void 0 : _config_environments1[environment];
|
|
169
|
+
if (!currentEnvironment) {
|
|
170
|
+
throw new Error(`Can not find environment '${environment}' when enabling SSR.`);
|
|
171
|
+
}
|
|
172
|
+
config.environments[SSR_ENV_NAME] = createSSRREnvConfig(currentEnvironment, moduleFederationOptions, ssrDir, config, callerName);
|
|
145
173
|
const ssgMDEnv = config.environments[RSPRESS_SSG_MD_ENV_NAME];
|
|
146
174
|
if (isRspress && ssgMDEnv) {
|
|
147
175
|
patchToolsTspack(ssgMDEnv, (config, { environment })=>{
|
|
@@ -149,8 +177,14 @@ const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
|
149
177
|
});
|
|
150
178
|
}
|
|
151
179
|
} else if (target === 'node') {
|
|
152
|
-
|
|
153
|
-
|
|
180
|
+
var _config_environments2;
|
|
181
|
+
const nodeTargetEnv = (_config_environments2 = config.environments) === null || _config_environments2 === void 0 ? void 0 : _config_environments2[environment];
|
|
182
|
+
if (!nodeTargetEnv) {
|
|
183
|
+
const availableEnvironments = Object.keys(config.environments || {});
|
|
184
|
+
const availableEnvironmentsLabel = availableEnvironments.length > 0 ? availableEnvironments.join(', ') : '(none)';
|
|
185
|
+
throw new Error(`Can not find environment '${environment}' when using target: 'node'. Available environments: ${availableEnvironmentsLabel}.`);
|
|
186
|
+
}
|
|
187
|
+
patchToolsTspack(nodeTargetEnv, (config, { environment })=>{
|
|
154
188
|
config.target = 'async-node';
|
|
155
189
|
});
|
|
156
190
|
}
|
|
@@ -227,7 +261,22 @@ const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
|
227
261
|
throw new Error('Can not get bundlerConfigs!');
|
|
228
262
|
}
|
|
229
263
|
bundlerConfigs.forEach((bundlerConfig)=>{
|
|
230
|
-
|
|
264
|
+
const bundlerConfigName = bundlerConfig.name || '';
|
|
265
|
+
const isConfiguredEnvironmentConfig = bundlerConfigName === environment;
|
|
266
|
+
const isNodeTargetEnvironmentConfig = target === 'node' && bundlerConfigName === environment;
|
|
267
|
+
const isRspressSSGEnvironmentConfig = isRspressSSGConfig(bundlerConfig.name);
|
|
268
|
+
const isActiveRspressSSGEnvironmentConfig = isRspress && isRspressSSGEnvironmentConfig;
|
|
269
|
+
const shouldUseSSRPluginConfig = isSSRConfig(bundlerConfig.name) || isNodeTargetEnvironmentConfig;
|
|
270
|
+
if (target === 'node' && !isNodeTargetEnvironmentConfig && !isActiveRspressSSGEnvironmentConfig) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
// For non-node targets, scope each plugin instance to its configured
|
|
274
|
+
// environment plus explicit SSR/SSG environments. This prevents a
|
|
275
|
+
// browser-targeted instance from mutating SSR configs.
|
|
276
|
+
if (target !== 'node' && !isConfiguredEnvironmentConfig && !shouldUseSSRPluginConfig && !isActiveRspressSSGEnvironmentConfig) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (!isMFFormat(bundlerConfig) && !isRspress && !isNodeTargetEnvironmentConfig) {
|
|
231
280
|
return;
|
|
232
281
|
} else if (isStoryBook(originalRsbuildConfig)) {
|
|
233
282
|
bundlerConfig.output.uniqueName = `${moduleFederationOptions.name} -storybook - host`;
|
|
@@ -235,7 +284,8 @@ const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
|
235
284
|
var _bundlerConfig_optimization, _bundlerConfig_optimization1, _bundlerConfig_output, _bundlerConfig_output1, _bundlerConfig_output2;
|
|
236
285
|
// mf
|
|
237
286
|
autoDeleteSplitChunkCacheGroups(moduleFederationOptions, bundlerConfig === null || bundlerConfig === void 0 ? void 0 : (_bundlerConfig_optimization = bundlerConfig.optimization) === null || _bundlerConfig_optimization === void 0 ? void 0 : _bundlerConfig_optimization.splitChunks);
|
|
238
|
-
addDataFetchExposes(moduleFederationOptions.exposes,
|
|
287
|
+
addDataFetchExposes(moduleFederationOptions.exposes, shouldUseSSRPluginConfig);
|
|
288
|
+
const ssrModuleFederationOptions = shouldUseSSRPluginConfig ? createSSRMFConfig(moduleFederationOptions) : undefined;
|
|
239
289
|
(_bundlerConfig_optimization1 = bundlerConfig.optimization) === null || _bundlerConfig_optimization1 === void 0 ? true : delete _bundlerConfig_optimization1.runtimeChunk;
|
|
240
290
|
const externals = bundlerConfig.externals;
|
|
241
291
|
if (Array.isArray(externals)) {
|
|
@@ -277,13 +327,12 @@ const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
|
277
327
|
}
|
|
278
328
|
}
|
|
279
329
|
}
|
|
280
|
-
if (!((_bundlerConfig_output = bundlerConfig.output) === null || _bundlerConfig_output === void 0 ? void 0 : _bundlerConfig_output.chunkLoadingGlobal) && !
|
|
330
|
+
if (!((_bundlerConfig_output = bundlerConfig.output) === null || _bundlerConfig_output === void 0 ? void 0 : _bundlerConfig_output.chunkLoadingGlobal) && !shouldUseSSRPluginConfig && !isActiveRspressSSGEnvironmentConfig && target !== 'node') {
|
|
281
331
|
bundlerConfig.output.chunkLoading = 'jsonp';
|
|
282
332
|
bundlerConfig.output.chunkLoadingGlobal = `chunk_${moduleFederationOptions.name} `;
|
|
283
333
|
}
|
|
284
|
-
if (
|
|
285
|
-
patchNodeConfig(bundlerConfig, moduleFederationOptions);
|
|
286
|
-
patchNodeMFConfig(moduleFederationOptions);
|
|
334
|
+
if (isNodeTargetEnvironmentConfig) {
|
|
335
|
+
patchNodeConfig(bundlerConfig, ssrModuleFederationOptions ?? moduleFederationOptions);
|
|
287
336
|
}
|
|
288
337
|
// `uniqueName` is required for react refresh to work
|
|
289
338
|
if (!((_bundlerConfig_output1 = bundlerConfig.output) === null || _bundlerConfig_output1 === void 0 ? void 0 : _bundlerConfig_output1.uniqueName)) {
|
|
@@ -291,17 +340,18 @@ const pluginModuleFederation = (moduleFederationOptions, rsbuildOptions)=>({
|
|
|
291
340
|
}
|
|
292
341
|
// Set default publicPath to 'auto' if not explicitly configured
|
|
293
342
|
// This allows remote chunks to load from the same origin as the remote application's manifest
|
|
294
|
-
if (((_bundlerConfig_output2 = bundlerConfig.output) === null || _bundlerConfig_output2 === void 0 ? void 0 : _bundlerConfig_output2.publicPath) === undefined && !
|
|
343
|
+
if (((_bundlerConfig_output2 = bundlerConfig.output) === null || _bundlerConfig_output2 === void 0 ? void 0 : _bundlerConfig_output2.publicPath) === undefined && !shouldUseSSRPluginConfig && !isActiveRspressSSGEnvironmentConfig) {
|
|
295
344
|
bundlerConfig.output.publicPath = 'auto';
|
|
296
345
|
}
|
|
297
346
|
if (!bundlerConfig.plugins.find((p)=>p && p.name === PLUGIN_NAME)) {
|
|
298
347
|
var _bundlerConfig_output3;
|
|
299
|
-
if (
|
|
300
|
-
|
|
348
|
+
if (shouldUseSSRPluginConfig) {
|
|
349
|
+
const ssrMFConfig = ssrModuleFederationOptions ?? createSSRMFConfig(moduleFederationOptions);
|
|
350
|
+
generateMergedStatsAndManifestOptions.options.nodePlugin = new ModuleFederationPlugin(ssrMFConfig);
|
|
301
351
|
generateMergedStatsAndManifestOptions.options.nodeEnvironmentName = bundlerConfig.name || SSR_ENV_NAME;
|
|
302
352
|
bundlerConfig.plugins.push(generateMergedStatsAndManifestOptions.options.nodePlugin);
|
|
303
353
|
return;
|
|
304
|
-
} else if (
|
|
354
|
+
} else if (isActiveRspressSSGEnvironmentConfig) {
|
|
305
355
|
const mfConfig = {
|
|
306
356
|
...createSSRMFConfig(moduleFederationOptions),
|
|
307
357
|
// expose in mf-ssg env
|
package/dist/utils/ssr.d.ts
CHANGED
|
@@ -28,7 +28,6 @@ export declare function createSSRMFConfig(mfConfig: moduleFederationPlugin.Modul
|
|
|
28
28
|
manifest?: boolean | moduleFederationPlugin.PluginManifestOptions;
|
|
29
29
|
dev?: boolean | moduleFederationPlugin.PluginDevOptions;
|
|
30
30
|
dts?: boolean | moduleFederationPlugin.PluginDtsOptions;
|
|
31
|
-
dataPrefetch?: moduleFederationPlugin.DataPrefetch;
|
|
32
31
|
virtualRuntimeEntry?: boolean;
|
|
33
32
|
experiments?: {
|
|
34
33
|
externalRuntime?: boolean;
|
package/dist/utils/ssr.js
CHANGED
|
@@ -81,6 +81,20 @@ const external_constant_js_namespaceObject = require("../constant.js");
|
|
|
81
81
|
|
|
82
82
|
const ssr_require = (0,external_node_module_namespaceObject.createRequire)(__rslib_import_meta_url__);
|
|
83
83
|
const resolve = ssr_require.resolve;
|
|
84
|
+
function resolveOrRequest(request) {
|
|
85
|
+
try {
|
|
86
|
+
return resolve(request);
|
|
87
|
+
} catch {
|
|
88
|
+
return request;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function safeRequire(request) {
|
|
92
|
+
try {
|
|
93
|
+
return ssr_require(request);
|
|
94
|
+
} catch {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
84
98
|
const SSR_DIR = 'ssr';
|
|
85
99
|
const SSR_ENV_NAME = 'mf-ssr';
|
|
86
100
|
const ENV_NAME = 'mf';
|
|
@@ -93,16 +107,27 @@ const isDev = ()=>{
|
|
|
93
107
|
function patchNodeConfig(config, mfConfig) {
|
|
94
108
|
var _config_output;
|
|
95
109
|
config.output ||= {};
|
|
110
|
+
if (config.output.publicPath === 'auto') {
|
|
111
|
+
config.output.publicPath = '';
|
|
112
|
+
}
|
|
96
113
|
config.target = 'async-node';
|
|
97
|
-
//
|
|
98
|
-
|
|
114
|
+
// Force node federation output to CJS + async chunk loading.
|
|
115
|
+
// This prevents browser jsonp runtime handlers from leaking into SSR remotes.
|
|
116
|
+
config.output.module = false;
|
|
117
|
+
config.output.chunkFormat = 'commonjs';
|
|
118
|
+
config.output.chunkLoading = 'async-node';
|
|
119
|
+
delete config.output.chunkLoadingGlobal;
|
|
120
|
+
const UniverseEntryChunkTrackerPluginModule = safeRequire('@module-federation/node/universe-entry-chunk-tracker-plugin');
|
|
121
|
+
const UniverseEntryChunkTrackerPlugin = UniverseEntryChunkTrackerPluginModule === null || UniverseEntryChunkTrackerPluginModule === void 0 ? void 0 : UniverseEntryChunkTrackerPluginModule.default;
|
|
99
122
|
config.plugins ||= [];
|
|
100
|
-
isDev() &&
|
|
123
|
+
if (isDev() && UniverseEntryChunkTrackerPlugin) {
|
|
124
|
+
config.plugins.push(new UniverseEntryChunkTrackerPlugin());
|
|
125
|
+
}
|
|
101
126
|
const uniqueName = mfConfig.name || ((_config_output = config.output) === null || _config_output === void 0 ? void 0 : _config_output.uniqueName);
|
|
102
127
|
const chunkFileName = config.output.chunkFilename;
|
|
103
128
|
if (typeof chunkFileName === 'string' && uniqueName && !chunkFileName.includes(uniqueName)) {
|
|
104
|
-
const
|
|
105
|
-
config.output.chunkFilename = chunkFileName.
|
|
129
|
+
const encodedName = (0,sdk_namespaceObject.encodeName)(uniqueName);
|
|
130
|
+
config.output.chunkFilename = chunkFileName.endsWith('.js') ? chunkFileName.replace(/\.js$/, `${encodedName}.js`) : `${chunkFileName}${encodedName}`;
|
|
106
131
|
}
|
|
107
132
|
}
|
|
108
133
|
function patchSSRRspackConfig(config, mfConfig, ssrDir, callerName, resetEntry = true, modifyPublicPath = true) {
|
|
@@ -113,11 +138,10 @@ function patchSSRRspackConfig(config, mfConfig, ssrDir, callerName, resetEntry =
|
|
|
113
138
|
throw new Error('publicPath must be string!');
|
|
114
139
|
}
|
|
115
140
|
const publicPath = config.output.publicPath;
|
|
116
|
-
if (publicPath
|
|
117
|
-
|
|
141
|
+
if (publicPath !== 'auto') {
|
|
142
|
+
const publicPathWithSSRDir = `${publicPath}${ssrDir}/`;
|
|
143
|
+
config.output.publicPath = publicPathWithSSRDir;
|
|
118
144
|
}
|
|
119
|
-
const publicPathWithSSRDir = `${publicPath}${ssrDir}/`;
|
|
120
|
-
config.output.publicPath = publicPathWithSSRDir;
|
|
121
145
|
}
|
|
122
146
|
if (callerName === external_constant_js_namespaceObject.CALL_NAME_MAP.RSPRESS && resetEntry) {
|
|
123
147
|
// set virtue entry, only need mf entry
|
|
@@ -196,10 +220,9 @@ function patchNodeMFConfig(mfConfig) {
|
|
|
196
220
|
mfConfig.runtimePlugins = [
|
|
197
221
|
...mfConfig.runtimePlugins || []
|
|
198
222
|
];
|
|
199
|
-
mfConfig.runtimePlugins.push(
|
|
223
|
+
mfConfig.runtimePlugins.push(resolveOrRequest('@module-federation/node/runtimePlugin'));
|
|
200
224
|
if (isDev()) {
|
|
201
|
-
mfConfig.runtimePlugins.push(
|
|
202
|
-
resolve('@module-federation/node/record-dynamic-remote-entry-hash-plugin'));
|
|
225
|
+
mfConfig.runtimePlugins.push(resolveOrRequest('@module-federation/node/record-dynamic-remote-entry-hash-plugin'));
|
|
203
226
|
}
|
|
204
227
|
}
|
|
205
228
|
function createSSRMFConfig(mfConfig) {
|
package/dist/utils/ssr.mjs
CHANGED
|
@@ -18,6 +18,20 @@ import { CALL_NAME_MAP } from "../constant.mjs";
|
|
|
18
18
|
|
|
19
19
|
const ssr_require = createRequire(import.meta.url);
|
|
20
20
|
const resolve = ssr_require.resolve;
|
|
21
|
+
function resolveOrRequest(request) {
|
|
22
|
+
try {
|
|
23
|
+
return resolve(request);
|
|
24
|
+
} catch {
|
|
25
|
+
return request;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function safeRequire(request) {
|
|
29
|
+
try {
|
|
30
|
+
return ssr_require(request);
|
|
31
|
+
} catch {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
21
35
|
const SSR_DIR = 'ssr';
|
|
22
36
|
const SSR_ENV_NAME = 'mf-ssr';
|
|
23
37
|
const ENV_NAME = 'mf';
|
|
@@ -30,16 +44,27 @@ const isDev = ()=>{
|
|
|
30
44
|
function patchNodeConfig(config, mfConfig) {
|
|
31
45
|
var _config_output;
|
|
32
46
|
config.output ||= {};
|
|
47
|
+
if (config.output.publicPath === 'auto') {
|
|
48
|
+
config.output.publicPath = '';
|
|
49
|
+
}
|
|
33
50
|
config.target = 'async-node';
|
|
34
|
-
//
|
|
35
|
-
|
|
51
|
+
// Force node federation output to CJS + async chunk loading.
|
|
52
|
+
// This prevents browser jsonp runtime handlers from leaking into SSR remotes.
|
|
53
|
+
config.output.module = false;
|
|
54
|
+
config.output.chunkFormat = 'commonjs';
|
|
55
|
+
config.output.chunkLoading = 'async-node';
|
|
56
|
+
delete config.output.chunkLoadingGlobal;
|
|
57
|
+
const UniverseEntryChunkTrackerPluginModule = safeRequire('@module-federation/node/universe-entry-chunk-tracker-plugin');
|
|
58
|
+
const UniverseEntryChunkTrackerPlugin = UniverseEntryChunkTrackerPluginModule === null || UniverseEntryChunkTrackerPluginModule === void 0 ? void 0 : UniverseEntryChunkTrackerPluginModule.default;
|
|
36
59
|
config.plugins ||= [];
|
|
37
|
-
isDev() &&
|
|
60
|
+
if (isDev() && UniverseEntryChunkTrackerPlugin) {
|
|
61
|
+
config.plugins.push(new UniverseEntryChunkTrackerPlugin());
|
|
62
|
+
}
|
|
38
63
|
const uniqueName = mfConfig.name || ((_config_output = config.output) === null || _config_output === void 0 ? void 0 : _config_output.uniqueName);
|
|
39
64
|
const chunkFileName = config.output.chunkFilename;
|
|
40
65
|
if (typeof chunkFileName === 'string' && uniqueName && !chunkFileName.includes(uniqueName)) {
|
|
41
|
-
const
|
|
42
|
-
config.output.chunkFilename = chunkFileName.
|
|
66
|
+
const encodedName = encodeName(uniqueName);
|
|
67
|
+
config.output.chunkFilename = chunkFileName.endsWith('.js') ? chunkFileName.replace(/\.js$/, `${encodedName}.js`) : `${chunkFileName}${encodedName}`;
|
|
43
68
|
}
|
|
44
69
|
}
|
|
45
70
|
function patchSSRRspackConfig(config, mfConfig, ssrDir, callerName, resetEntry = true, modifyPublicPath = true) {
|
|
@@ -50,11 +75,10 @@ function patchSSRRspackConfig(config, mfConfig, ssrDir, callerName, resetEntry =
|
|
|
50
75
|
throw new Error('publicPath must be string!');
|
|
51
76
|
}
|
|
52
77
|
const publicPath = config.output.publicPath;
|
|
53
|
-
if (publicPath
|
|
54
|
-
|
|
78
|
+
if (publicPath !== 'auto') {
|
|
79
|
+
const publicPathWithSSRDir = `${publicPath}${ssrDir}/`;
|
|
80
|
+
config.output.publicPath = publicPathWithSSRDir;
|
|
55
81
|
}
|
|
56
|
-
const publicPathWithSSRDir = `${publicPath}${ssrDir}/`;
|
|
57
|
-
config.output.publicPath = publicPathWithSSRDir;
|
|
58
82
|
}
|
|
59
83
|
if (callerName === CALL_NAME_MAP.RSPRESS && resetEntry) {
|
|
60
84
|
// set virtue entry, only need mf entry
|
|
@@ -133,10 +157,9 @@ function patchNodeMFConfig(mfConfig) {
|
|
|
133
157
|
mfConfig.runtimePlugins = [
|
|
134
158
|
...mfConfig.runtimePlugins || []
|
|
135
159
|
];
|
|
136
|
-
mfConfig.runtimePlugins.push(
|
|
160
|
+
mfConfig.runtimePlugins.push(resolveOrRequest('@module-federation/node/runtimePlugin'));
|
|
137
161
|
if (isDev()) {
|
|
138
|
-
mfConfig.runtimePlugins.push(
|
|
139
|
-
resolve('@module-federation/node/record-dynamic-remote-entry-hash-plugin'));
|
|
162
|
+
mfConfig.runtimePlugins.push(resolveOrRequest('@module-federation/node/record-dynamic-remote-entry-hash-plugin'));
|
|
140
163
|
}
|
|
141
164
|
}
|
|
142
165
|
function createSSRMFConfig(mfConfig) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@module-federation/rsbuild-plugin",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Module Federation plugin for Rsbuild",
|
|
5
5
|
"homepage": "https://module-federation.io",
|
|
6
6
|
"bugs": {
|
|
@@ -50,16 +50,16 @@
|
|
|
50
50
|
],
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"fs-extra": "11.3.0",
|
|
53
|
-
"@module-federation/
|
|
54
|
-
"@module-federation/
|
|
55
|
-
"@module-federation/
|
|
53
|
+
"@module-federation/enhanced": "2.2.0",
|
|
54
|
+
"@module-federation/node": "2.7.34",
|
|
55
|
+
"@module-federation/sdk": "2.2.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@rslib/core": "^0.12.4",
|
|
59
59
|
"@rsbuild/core": "2.0.0-beta.2"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
|
-
"@rsbuild/core": "2.0.0-
|
|
62
|
+
"@rsbuild/core": "^1.3.21 || ^2.0.0-0"
|
|
63
63
|
},
|
|
64
64
|
"peerDependenciesMeta": {
|
|
65
65
|
"@rsbuild/core": {
|
|
@@ -72,5 +72,11 @@
|
|
|
72
72
|
"publishConfig": {
|
|
73
73
|
"access": "public",
|
|
74
74
|
"registry": "https://registry.npmjs.org/"
|
|
75
|
+
},
|
|
76
|
+
"scripts": {
|
|
77
|
+
"build": "rslib build",
|
|
78
|
+
"lint": "ESLINT_USE_FLAT_CONFIG=false pnpm exec eslint --ignore-pattern node_modules \"**/*.ts\" \"package.json\"",
|
|
79
|
+
"test": "pnpm exec vitest run --passWithNoTests --config vite.config.mts",
|
|
80
|
+
"pre-release": "pnpm run test && pnpm run build"
|
|
75
81
|
}
|
|
76
82
|
}
|