@nx/react 19.7.0-canary.20240905-ccda7f9 → 19.7.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/executors.json +5 -0
- package/package.json +8 -6
- package/src/executors/module-federation-dev-server/module-federation-dev-server.impl.d.ts +1 -14
- package/src/executors/module-federation-dev-server/module-federation-dev-server.impl.js +2 -60
- package/src/executors/module-federation-dev-server/schema.d.ts +17 -0
- package/src/executors/module-federation-static-server/module-federation-static-server.impl.d.ts +12 -0
- package/src/executors/module-federation-static-server/module-federation-static-server.impl.js +240 -0
- package/src/executors/module-federation-static-server/schema.d.ts +3 -0
- package/src/executors/module-federation-static-server/schema.json +14 -0
- package/src/generators/application/application.js +4 -1
- package/src/generators/application/lib/add-routing.js +4 -1
- package/src/generators/application/lib/create-application-files.js +5 -2
- package/src/generators/federate-module/federate-module.js +5 -1
- package/src/generators/federate-module/schema.d.ts +1 -0
- package/src/generators/federate-module/schema.json +6 -0
- package/src/generators/host/files/rspack-common/src/app/__fileName__.jsx__tmpl__ +33 -0
- package/src/generators/host/files/rspack-common/src/main.jsx__tmpl__ +10 -0
- package/src/generators/host/files/rspack-module-federation/rspack.config.js__tmpl__ +16 -0
- package/src/generators/host/files/rspack-module-federation/rspack.config.prod.js__tmpl__ +36 -0
- package/src/generators/host/files/rspack-module-federation-ssr/module-federation.server.config.js__tmpl__ +16 -0
- package/src/generators/host/files/rspack-module-federation-ssr/rspack.server.config.js__tmpl__ +16 -0
- package/src/generators/host/files/rspack-module-federation-ssr-ts/module-federation.server.config.ts__tmpl__ +13 -0
- package/src/generators/host/files/rspack-module-federation-ssr-ts/rspack.server.config.ts__tmpl__ +16 -0
- package/src/generators/host/files/rspack-module-federation-ts/module-federation.config.ts__tmpl__ +25 -0
- package/src/generators/host/files/rspack-module-federation-ts/rspack.config.prod.ts__tmpl__ +36 -0
- package/src/generators/host/files/rspack-module-federation-ts/rspack.config.ts__tmpl__ +16 -0
- package/src/generators/host/files/webpack-module-federation/module-federation.config.js__tmpl__ +21 -0
- package/src/generators/host/files/webpack-module-federation-ssr/server.ts__tmpl__ +28 -0
- package/src/generators/host/files/webpack-module-federation-ssr/tsconfig.server.json__tmpl__ +17 -0
- package/src/generators/host/files/webpack-module-federation-ssr-ts/server.ts__tmpl__ +28 -0
- package/src/generators/host/files/webpack-module-federation-ssr-ts/tsconfig.server.json__tmpl__ +17 -0
- package/src/generators/host/host.js +10 -3
- package/src/generators/host/lib/add-module-federation-files.js +23 -11
- package/src/generators/host/lib/setup-ssr-for-host.js +6 -3
- package/src/generators/host/schema.d.ts +1 -0
- package/src/generators/host/schema.json +8 -0
- package/src/generators/remote/files/rspack-common/src/main.jsx__tmpl__ +1 -0
- package/src/generators/remote/files/rspack-common/src/remote-entry.js__tmpl__ +1 -0
- package/src/generators/remote/files/rspack-module-federation/rspack.config.js__tmpl__ +16 -0
- package/src/generators/remote/files/rspack-module-federation/rspack.config.prod.js__tmpl__ +1 -0
- package/src/generators/remote/files/rspack-module-federation-ssr/module-federation.server.config.js__tmpl__ +6 -0
- package/src/generators/remote/files/rspack-module-federation-ssr/rspack.server.config.js__tmpl__ +16 -0
- package/src/generators/remote/files/rspack-module-federation-ssr-ts/module-federation.server.config.ts__tmpl__ +10 -0
- package/src/generators/remote/files/rspack-module-federation-ssr-ts/rspack.server.config.ts__tmpl__ +16 -0
- package/src/generators/remote/files/rspack-module-federation-ssr-ts/tsconfig.lint.json__tmpl__ +19 -0
- package/src/generators/remote/files/rspack-module-federation-ts/module-federation.config.ts__tmpl__ +13 -0
- package/src/generators/remote/files/rspack-module-federation-ts/rspack.config.prod.ts__tmpl__ +1 -0
- package/src/generators/remote/files/rspack-module-federation-ts/rspack.config.ts__tmpl__ +16 -0
- package/src/generators/remote/files/rspack-module-federation-ts/tsconfig.lint.json__tmpl__ +19 -0
- package/src/generators/remote/files/webpack-module-federation/module-federation.config.js__tmpl__ +9 -0
- package/src/generators/remote/files/webpack-module-federation-ssr/server.ts__tmpl__ +45 -0
- package/src/generators/remote/files/webpack-module-federation-ssr-ts/server.ts__tmpl__ +45 -0
- package/src/generators/remote/files/webpack-module-federation-ts/tsconfig.lint.json__tmpl__ +19 -0
- package/src/generators/remote/lib/setup-ssr-for-remote.js +2 -2
- package/src/generators/remote/lib/update-host-with-remote.js +4 -0
- package/src/generators/remote/remote.js +24 -11
- package/src/generators/remote/schema.d.ts +1 -0
- package/src/generators/remote/schema.json +8 -0
- package/src/generators/setup-ssr/schema.d.ts +1 -0
- package/src/generators/setup-ssr/schema.json +6 -0
- package/src/generators/setup-ssr/setup-ssr.js +11 -3
- package/src/module-federation/utils.js +1 -1
- package/src/module-federation/with-module-federation.js +2 -11
- package/src/rules/update-module-federation-project.d.ts +3 -2
- package/src/rules/update-module-federation-project.js +54 -23
- package/src/utils/build-static.remotes.d.ts +4 -0
- package/src/utils/build-static.remotes.js +65 -0
- package/src/utils/maybe-js.d.ts +1 -0
- package/src/utils/maybe-js.js +1 -1
- /package/src/generators/{remote/files/module-federation-ssr-ts → host/files/rspack-common}/tsconfig.lint.json__tmpl__ +0 -0
- /package/src/generators/host/files/{module-federation → rspack-module-federation}/module-federation.config.js__tmpl__ +0 -0
- /package/src/generators/host/files/{module-federation-ssr → rspack-module-federation-ssr}/server.ts__tmpl__ +0 -0
- /package/src/generators/host/files/{module-federation-ssr → rspack-module-federation-ssr}/tsconfig.server.json__tmpl__ +0 -0
- /package/src/generators/host/files/{module-federation-ssr-ts → rspack-module-federation-ssr-ts}/server.ts__tmpl__ +0 -0
- /package/src/generators/host/files/{module-federation-ssr-ts → rspack-module-federation-ssr-ts}/tsconfig.server.json__tmpl__ +0 -0
- /package/src/generators/host/files/{module-federation → webpack-module-federation}/webpack.config.js__tmpl__ +0 -0
- /package/src/generators/host/files/{module-federation → webpack-module-federation}/webpack.config.prod.js__tmpl__ +0 -0
- /package/src/generators/host/files/{module-federation-ssr → webpack-module-federation-ssr}/module-federation.server.config.js__tmpl__ +0 -0
- /package/src/generators/host/files/{module-federation-ssr → webpack-module-federation-ssr}/webpack.server.config.js__tmpl__ +0 -0
- /package/src/generators/host/files/{module-federation-ssr-ts → webpack-module-federation-ssr-ts}/module-federation.server.config.ts__tmpl__ +0 -0
- /package/src/generators/host/files/{module-federation-ssr-ts → webpack-module-federation-ssr-ts}/webpack.server.config.ts__tmpl__ +0 -0
- /package/src/generators/host/files/{module-federation-ts → webpack-module-federation-ts}/module-federation.config.ts__tmpl__ +0 -0
- /package/src/generators/host/files/{module-federation-ts → webpack-module-federation-ts}/webpack.config.prod.ts__tmpl__ +0 -0
- /package/src/generators/host/files/{module-federation-ts → webpack-module-federation-ts}/webpack.config.ts__tmpl__ +0 -0
- /package/src/generators/remote/files/{module-federation → rspack-module-federation}/module-federation.config.js__tmpl__ +0 -0
- /package/src/generators/remote/files/{module-federation-ssr → rspack-module-federation-ssr}/server.ts__tmpl__ +0 -0
- /package/src/generators/remote/files/{module-federation-ssr-ts → rspack-module-federation-ssr-ts}/server.ts__tmpl__ +0 -0
- /package/src/generators/remote/files/{module-federation → webpack-module-federation}/webpack.config.js__tmpl__ +0 -0
- /package/src/generators/remote/files/{module-federation → webpack-module-federation}/webpack.config.prod.js__tmpl__ +0 -0
- /package/src/generators/remote/files/{module-federation-ssr → webpack-module-federation-ssr}/module-federation.server.config.js__tmpl__ +0 -0
- /package/src/generators/remote/files/{module-federation-ssr → webpack-module-federation-ssr}/webpack.server.config.js__tmpl__ +0 -0
- /package/src/generators/remote/files/{module-federation-ssr-ts → webpack-module-federation-ssr-ts}/module-federation.server.config.ts__tmpl__ +0 -0
- /package/src/generators/remote/files/{module-federation-ts → webpack-module-federation-ssr-ts}/tsconfig.lint.json__tmpl__ +0 -0
- /package/src/generators/remote/files/{module-federation-ssr-ts → webpack-module-federation-ssr-ts}/webpack.server.config.ts__tmpl__ +0 -0
- /package/src/generators/remote/files/{module-federation-ts → webpack-module-federation-ts}/module-federation.config.ts__tmpl__ +0 -0
- /package/src/generators/remote/files/{module-federation-ts → webpack-module-federation-ts}/webpack.config.prod.ts__tmpl__ +0 -0
- /package/src/generators/remote/files/{module-federation-ts → webpack-module-federation-ts}/webpack.config.ts__tmpl__ +0 -0
package/executors.json
CHANGED
@@ -9,6 +9,11 @@
|
|
9
9
|
"implementation": "./src/executors/module-federation-ssr-dev-server/module-federation-ssr-dev-server.impl",
|
10
10
|
"schema": "./src/executors/module-federation-ssr-dev-server/schema.json",
|
11
11
|
"description": "Serve a host application along with it's known remotes."
|
12
|
+
},
|
13
|
+
"module-federation-static-server": {
|
14
|
+
"implementation": "./src/executors/module-federation-static-server/module-federation-static-server.impl",
|
15
|
+
"schema": "./src/executors/module-federation-static-server/schema.json",
|
16
|
+
"description": "Serve a host and its remotes statically."
|
12
17
|
}
|
13
18
|
}
|
14
19
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@nx/react",
|
3
|
-
"version": "19.7.0
|
3
|
+
"version": "19.7.0",
|
4
4
|
"private": false,
|
5
5
|
"description": "The React plugin for Nx contains executors and generators for managing React applications and libraries within an Nx workspace. It provides:\n\n\n- Integration with libraries such as Jest, Vitest, Playwright, Cypress, and Storybook.\n\n- Generators for applications, libraries, components, hooks, and more.\n\n- Library build support for publishing packages to npm or other registries.\n\n- Utilities for automatic workspace refactoring.",
|
6
6
|
"repository": {
|
@@ -39,11 +39,13 @@
|
|
39
39
|
"minimatch": "9.0.3",
|
40
40
|
"tslib": "^2.3.0",
|
41
41
|
"@module-federation/enhanced": "~0.6.0",
|
42
|
-
"@nx/devkit": "19.7.0
|
43
|
-
"@nx/js": "19.7.0
|
44
|
-
"@nx/eslint": "19.7.0
|
45
|
-
"@nx/web": "19.7.0
|
46
|
-
"
|
42
|
+
"@nx/devkit": "19.7.0",
|
43
|
+
"@nx/js": "19.7.0",
|
44
|
+
"@nx/eslint": "19.7.0",
|
45
|
+
"@nx/web": "19.7.0",
|
46
|
+
"express": "^4.19.2",
|
47
|
+
"http-proxy-middleware": "^3.0.0",
|
48
|
+
"@nrwl/react": "19.7.0"
|
47
49
|
},
|
48
50
|
"publishConfig": {
|
49
51
|
"access": "public"
|
@@ -1,19 +1,6 @@
|
|
1
1
|
import { ExecutorContext } from '@nx/devkit';
|
2
|
-
import {
|
3
|
-
type ModuleFederationDevServerOptions = WebDevServerOptions & {
|
4
|
-
devRemotes?: (string | {
|
5
|
-
remoteName: string;
|
6
|
-
configuration: string;
|
7
|
-
})[];
|
8
|
-
skipRemotes?: string[];
|
9
|
-
static?: boolean;
|
10
|
-
isInitialHost?: boolean;
|
11
|
-
parallel?: number;
|
12
|
-
staticRemotesPort?: number;
|
13
|
-
pathToManifestFile?: string;
|
14
|
-
};
|
2
|
+
import { ModuleFederationDevServerOptions } from './schema';
|
15
3
|
export default function moduleFederationDevServer(options: ModuleFederationDevServerOptions, context: ExecutorContext): AsyncIterableIterator<{
|
16
4
|
success: boolean;
|
17
5
|
baseUrl?: string;
|
18
6
|
}>;
|
19
|
-
export {};
|
@@ -7,12 +7,11 @@ const file_server_impl_1 = require("@nx/web/src/executors/file-server/file-serve
|
|
7
7
|
const module_federation_1 = require("@nx/webpack/src/utils/module-federation");
|
8
8
|
const async_iterable_1 = require("@nx/devkit/src/utils/async-iterable");
|
9
9
|
const wait_for_port_open_1 = require("@nx/web/src/utils/wait-for-port-open");
|
10
|
-
const cache_directory_1 = require("nx/src/utils/cache-directory");
|
11
|
-
const node_child_process_1 = require("node:child_process");
|
12
10
|
const fs_1 = require("fs");
|
13
11
|
const path_1 = require("path");
|
14
12
|
const start_remote_proxies_1 = require("@nx/webpack/src/utils/module-federation/start-remote-proxies");
|
15
13
|
const parse_static_remotes_config_1 = require("@nx/webpack/src/utils/module-federation/parse-static-remotes-config");
|
14
|
+
const build_static_remotes_1 = require("../../utils/build-static.remotes");
|
16
15
|
function getBuildOptions(buildTarget, context) {
|
17
16
|
const target = (0, devkit_1.parseTargetString)(buildTarget, context);
|
18
17
|
const buildOptions = (0, devkit_1.readTargetOptions)(target, context);
|
@@ -92,63 +91,6 @@ async function startRemotes(remotes, context, options, target = 'serve') {
|
|
92
91
|
}
|
93
92
|
return remoteIters;
|
94
93
|
}
|
95
|
-
async function buildStaticRemotes(staticRemotesConfig, nxBin, context, options) {
|
96
|
-
if (!staticRemotesConfig.remotes.length) {
|
97
|
-
return;
|
98
|
-
}
|
99
|
-
devkit_1.logger.info(`NX Building ${staticRemotesConfig.remotes.length} static remotes...`);
|
100
|
-
const mappedLocationOfRemotes = {};
|
101
|
-
for (const app of staticRemotesConfig.remotes) {
|
102
|
-
mappedLocationOfRemotes[app] = `http${options.ssl ? 's' : ''}://${options.host}:${options.staticRemotesPort}/${staticRemotesConfig.config[app].urlSegment}`;
|
103
|
-
}
|
104
|
-
await new Promise((res, rej) => {
|
105
|
-
const staticProcess = (0, node_child_process_1.fork)(nxBin, [
|
106
|
-
'run-many',
|
107
|
-
`--target=build`,
|
108
|
-
`--projects=${staticRemotesConfig.remotes.join(',')}`,
|
109
|
-
...(context.configurationName
|
110
|
-
? [`--configuration=${context.configurationName}`]
|
111
|
-
: []),
|
112
|
-
...(options.parallel ? [`--parallel=${options.parallel}`] : []),
|
113
|
-
], {
|
114
|
-
cwd: context.root,
|
115
|
-
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
116
|
-
});
|
117
|
-
// File to debug build failures e.g. 2024-01-01T00_00_0_0Z-build.log'
|
118
|
-
const remoteBuildLogFile = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, `${new Date().toISOString().replace(/[:\.]/g, '_')}-build.log`);
|
119
|
-
const stdoutStream = (0, fs_1.createWriteStream)(remoteBuildLogFile);
|
120
|
-
staticProcess.stdout.on('data', (data) => {
|
121
|
-
const ANSII_CODE_REGEX = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
122
|
-
const stdoutString = data.toString().replace(ANSII_CODE_REGEX, '');
|
123
|
-
stdoutStream.write(stdoutString);
|
124
|
-
// in addition to writing into the stdout stream, also show error directly in console
|
125
|
-
// so the error is easily discoverable. 'ERROR in' is the key word to search in webpack output.
|
126
|
-
if (stdoutString.includes('ERROR in')) {
|
127
|
-
devkit_1.logger.log(stdoutString);
|
128
|
-
}
|
129
|
-
if (stdoutString.includes('Successfully ran target build')) {
|
130
|
-
staticProcess.stdout.removeAllListeners('data');
|
131
|
-
devkit_1.logger.info(`NX Built ${staticRemotesConfig.remotes.length} static remotes`);
|
132
|
-
res();
|
133
|
-
}
|
134
|
-
});
|
135
|
-
staticProcess.stderr.on('data', (data) => devkit_1.logger.info(data.toString()));
|
136
|
-
staticProcess.once('exit', (code) => {
|
137
|
-
stdoutStream.end();
|
138
|
-
staticProcess.stdout.removeAllListeners('data');
|
139
|
-
staticProcess.stderr.removeAllListeners('data');
|
140
|
-
if (code !== 0) {
|
141
|
-
rej(`Remote failed to start. A complete log can be found in: ${remoteBuildLogFile}`);
|
142
|
-
}
|
143
|
-
else {
|
144
|
-
res();
|
145
|
-
}
|
146
|
-
});
|
147
|
-
process.on('SIGTERM', () => staticProcess.kill('SIGTERM'));
|
148
|
-
process.on('exit', () => staticProcess.kill('SIGTERM'));
|
149
|
-
});
|
150
|
-
return mappedLocationOfRemotes;
|
151
|
-
}
|
152
94
|
async function* moduleFederationDevServer(options, context) {
|
153
95
|
// Force Node to resolve to look for the nx binary that is inside node_modules
|
154
96
|
const nxBin = require.resolve('nx/bin/nx');
|
@@ -192,7 +134,7 @@ async function* moduleFederationDevServer(options, context) {
|
|
192
134
|
p.name,
|
193
135
|
]);
|
194
136
|
const staticRemotesConfig = (0, parse_static_remotes_config_1.parseStaticRemotesConfig)([...remotes.staticRemotes, ...remotes.dynamicRemotes], context);
|
195
|
-
const mappedLocationsOfStaticRemotes = await buildStaticRemotes(staticRemotesConfig, nxBin, context, options);
|
137
|
+
const mappedLocationsOfStaticRemotes = await (0, build_static_remotes_1.buildStaticRemotes)(staticRemotesConfig, nxBin, context, options);
|
196
138
|
const devRemoteIters = await startRemotes(remotes.devRemotes, context, options, 'serve');
|
197
139
|
const staticRemotesIter = startStaticRemotesFileServer(staticRemotesConfig, context, options);
|
198
140
|
(0, start_remote_proxies_1.startRemoteProxies)(staticRemotesConfig, mappedLocationsOfStaticRemotes, options.ssl
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { WebDevServerOptions } from '@nx/webpack';
|
2
|
+
|
3
|
+
export type ModuleFederationDevServerOptions = WebDevServerOptions & {
|
4
|
+
devRemotes?: (
|
5
|
+
| string
|
6
|
+
| {
|
7
|
+
remoteName: string;
|
8
|
+
configuration: string;
|
9
|
+
}
|
10
|
+
)[];
|
11
|
+
skipRemotes?: string[];
|
12
|
+
static?: boolean;
|
13
|
+
isInitialHost?: boolean;
|
14
|
+
parallel?: number;
|
15
|
+
staticRemotesPort?: number;
|
16
|
+
pathToManifestFile?: string;
|
17
|
+
};
|
package/src/executors/module-federation-static-server/module-federation-static-server.impl.d.ts
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
import { ModuleFederationStaticServerSchema } from './schema';
|
2
|
+
import { ModuleFederationDevServerOptions } from '../module-federation-dev-server/schema';
|
3
|
+
import { ExecutorContext } from 'nx/src/config/misc-interfaces';
|
4
|
+
import { StaticRemotesConfig } from '@nx/webpack/src/utils/module-federation/parse-static-remotes-config';
|
5
|
+
export declare function startProxies(staticRemotesConfig: StaticRemotesConfig, hostServeOptions: ModuleFederationDevServerOptions, mappedLocationOfHost: string, mappedLocationsOfRemotes: Record<string, string>, sslOptions?: {
|
6
|
+
pathToCert: string;
|
7
|
+
pathToKey: string;
|
8
|
+
}): void;
|
9
|
+
export default function moduleFederationStaticServer(schema: ModuleFederationStaticServerSchema, context: ExecutorContext): AsyncGenerator<{
|
10
|
+
success: boolean;
|
11
|
+
baseUrl: string;
|
12
|
+
}, any, unknown>;
|
@@ -0,0 +1,240 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.startProxies = startProxies;
|
4
|
+
exports.default = moduleFederationStaticServer;
|
5
|
+
const path_1 = require("path");
|
6
|
+
const devkit_1 = require("@nx/devkit");
|
7
|
+
const fs_1 = require("fs");
|
8
|
+
const module_federation_1 = require("@nx/webpack/src/utils/module-federation");
|
9
|
+
const parse_static_remotes_config_1 = require("@nx/webpack/src/utils/module-federation/parse-static-remotes-config");
|
10
|
+
const build_static_remotes_1 = require("../../utils/build-static.remotes");
|
11
|
+
const child_process_1 = require("child_process");
|
12
|
+
const process = require("node:process");
|
13
|
+
const file_server_impl_1 = require("@nx/web/src/executors/file-server/file-server.impl");
|
14
|
+
const async_iterable_1 = require("@nx/devkit/src/utils/async-iterable");
|
15
|
+
const wait_for_port_open_1 = require("@nx/web/src/utils/wait-for-port-open");
|
16
|
+
function getBuildAndServeOptionsFromServeTarget(serveTarget, context) {
|
17
|
+
const target = (0, devkit_1.parseTargetString)(serveTarget, context);
|
18
|
+
const serveOptions = (0, devkit_1.readTargetOptions)(target, context);
|
19
|
+
const buildTarget = (0, devkit_1.parseTargetString)(serveOptions.buildTarget, context);
|
20
|
+
const buildOptions = (0, devkit_1.readTargetOptions)(buildTarget, context);
|
21
|
+
let pathToManifestFile = (0, path_1.join)(context.root, context.projectGraph.nodes[context.projectName].data.sourceRoot, 'assets/module-federation.manifest.json');
|
22
|
+
if (serveOptions.pathToManifestFile) {
|
23
|
+
const userPathToManifestFile = (0, path_1.join)(context.root, serveOptions.pathToManifestFile);
|
24
|
+
if (!(0, fs_1.existsSync)(userPathToManifestFile)) {
|
25
|
+
throw new Error(`The provided Module Federation manifest file path does not exist. Please check the file exists at "${userPathToManifestFile}".`);
|
26
|
+
}
|
27
|
+
else if ((0, path_1.extname)(serveOptions.pathToManifestFile) !== '.json') {
|
28
|
+
throw new Error(`The Module Federation manifest file must be a JSON. Please ensure the file at ${userPathToManifestFile} is a JSON.`);
|
29
|
+
}
|
30
|
+
pathToManifestFile = userPathToManifestFile;
|
31
|
+
}
|
32
|
+
return {
|
33
|
+
buildTarget,
|
34
|
+
buildOptions,
|
35
|
+
serveOptions,
|
36
|
+
pathToManifestFile,
|
37
|
+
};
|
38
|
+
}
|
39
|
+
async function buildHost(nxBin, buildTarget, context) {
|
40
|
+
await new Promise((res, rej) => {
|
41
|
+
const staticProcess = (0, child_process_1.fork)(nxBin, [
|
42
|
+
`run`,
|
43
|
+
`${buildTarget.project}:${buildTarget.target}${buildTarget.configuration
|
44
|
+
? `:${buildTarget.configuration}`
|
45
|
+
: context.configurationName
|
46
|
+
? `:${context.configurationName}`
|
47
|
+
: ''}`,
|
48
|
+
], {
|
49
|
+
cwd: context.root,
|
50
|
+
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
51
|
+
});
|
52
|
+
staticProcess.stdout.on('data', (data) => {
|
53
|
+
const ANSII_CODE_REGEX = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
54
|
+
const stdoutString = data.toString().replace(ANSII_CODE_REGEX, '');
|
55
|
+
// in addition to writing into the stdout stream, also show error directly in console
|
56
|
+
// so the error is easily discoverable. 'ERROR in' is the key word to search in webpack output.
|
57
|
+
if (stdoutString.includes('ERROR in')) {
|
58
|
+
devkit_1.logger.log(stdoutString);
|
59
|
+
}
|
60
|
+
if (stdoutString.includes('Successfully ran target build')) {
|
61
|
+
staticProcess.stdout.removeAllListeners('data');
|
62
|
+
devkit_1.logger.info(`NX Built host`);
|
63
|
+
res();
|
64
|
+
}
|
65
|
+
});
|
66
|
+
staticProcess.stderr.on('data', (data) => devkit_1.logger.info(data.toString()));
|
67
|
+
staticProcess.once('exit', (code) => {
|
68
|
+
staticProcess.stdout.removeAllListeners('data');
|
69
|
+
staticProcess.stderr.removeAllListeners('data');
|
70
|
+
if (code !== 0) {
|
71
|
+
rej(`Host failed to build. See above for details.`);
|
72
|
+
}
|
73
|
+
else {
|
74
|
+
res();
|
75
|
+
}
|
76
|
+
});
|
77
|
+
process.on('SIGTERM', () => staticProcess.kill('SIGTERM'));
|
78
|
+
process.on('exit', () => staticProcess.kill('SIGTERM'));
|
79
|
+
});
|
80
|
+
}
|
81
|
+
function moveToTmpDirectory(staticRemotesConfig, hostOutputPath, hostUrlSegment) {
|
82
|
+
const commonOutputDirectory = (0, path_1.join)(devkit_1.workspaceRoot, 'tmp/static-module-federation');
|
83
|
+
for (const app of staticRemotesConfig.remotes) {
|
84
|
+
const remoteConfig = staticRemotesConfig.config[app];
|
85
|
+
(0, fs_1.cpSync)(remoteConfig.outputPath, (0, path_1.join)(commonOutputDirectory, remoteConfig.urlSegment), {
|
86
|
+
force: true,
|
87
|
+
recursive: true,
|
88
|
+
});
|
89
|
+
}
|
90
|
+
(0, fs_1.cpSync)(hostOutputPath, (0, path_1.join)(commonOutputDirectory, hostUrlSegment), {
|
91
|
+
force: true,
|
92
|
+
recursive: true,
|
93
|
+
});
|
94
|
+
const cleanup = () => {
|
95
|
+
(0, fs_1.rmSync)(commonOutputDirectory, { force: true, recursive: true });
|
96
|
+
};
|
97
|
+
process.on('SIGTERM', () => {
|
98
|
+
cleanup();
|
99
|
+
});
|
100
|
+
process.on('exit', () => {
|
101
|
+
cleanup();
|
102
|
+
});
|
103
|
+
return commonOutputDirectory;
|
104
|
+
}
|
105
|
+
function startProxies(staticRemotesConfig, hostServeOptions, mappedLocationOfHost, mappedLocationsOfRemotes, sslOptions) {
|
106
|
+
const { createProxyMiddleware } = require('http-proxy-middleware');
|
107
|
+
const express = require('express');
|
108
|
+
let sslCert;
|
109
|
+
let sslKey;
|
110
|
+
if (sslOptions && sslOptions.pathToCert && sslOptions.pathToKey) {
|
111
|
+
if ((0, fs_1.existsSync)(sslOptions.pathToCert) && (0, fs_1.existsSync)(sslOptions.pathToKey)) {
|
112
|
+
sslCert = (0, fs_1.readFileSync)(sslOptions.pathToCert);
|
113
|
+
sslKey = (0, fs_1.readFileSync)(sslOptions.pathToKey);
|
114
|
+
}
|
115
|
+
else {
|
116
|
+
devkit_1.logger.warn(`Encountered SSL options in project.json, however, the certificate files do not exist in the filesystem. Using http.`);
|
117
|
+
devkit_1.logger.warn(`Attempted to find '${sslOptions.pathToCert}' and '${sslOptions.pathToKey}'.`);
|
118
|
+
}
|
119
|
+
}
|
120
|
+
const http = require('http');
|
121
|
+
const https = require('https');
|
122
|
+
devkit_1.logger.info(`NX Starting static remotes proxies...`);
|
123
|
+
for (const app of staticRemotesConfig.remotes) {
|
124
|
+
const expressProxy = express();
|
125
|
+
expressProxy.use(createProxyMiddleware({
|
126
|
+
target: mappedLocationsOfRemotes[app],
|
127
|
+
changeOrigin: true,
|
128
|
+
secure: sslCert ? false : undefined,
|
129
|
+
}));
|
130
|
+
const proxyServer = (sslCert ? https : http)
|
131
|
+
.createServer({ cert: sslCert, key: sslKey }, expressProxy)
|
132
|
+
.listen(staticRemotesConfig.config[app].port);
|
133
|
+
process.on('SIGTERM', () => proxyServer.close());
|
134
|
+
process.on('exit', () => proxyServer.close());
|
135
|
+
}
|
136
|
+
devkit_1.logger.info(`NX Static remotes proxies started successfully`);
|
137
|
+
devkit_1.logger.info(`NX Starting static host proxy...`);
|
138
|
+
const expressProxy = express();
|
139
|
+
expressProxy.use(createProxyMiddleware({
|
140
|
+
target: mappedLocationOfHost,
|
141
|
+
changeOrigin: true,
|
142
|
+
secure: sslCert ? false : undefined,
|
143
|
+
pathRewrite: (path) => {
|
144
|
+
let pathRewrite = path;
|
145
|
+
for (const app of staticRemotesConfig.remotes) {
|
146
|
+
if (path.endsWith(app)) {
|
147
|
+
pathRewrite = '/';
|
148
|
+
break;
|
149
|
+
}
|
150
|
+
}
|
151
|
+
return pathRewrite;
|
152
|
+
},
|
153
|
+
}));
|
154
|
+
const proxyServer = (sslCert ? https : http)
|
155
|
+
.createServer({ cert: sslCert, key: sslKey }, expressProxy)
|
156
|
+
.listen(hostServeOptions.port);
|
157
|
+
process.on('SIGTERM', () => proxyServer.close());
|
158
|
+
process.on('exit', () => proxyServer.close());
|
159
|
+
devkit_1.logger.info('NX Static host proxy started successfully');
|
160
|
+
}
|
161
|
+
async function* moduleFederationStaticServer(schema, context) {
|
162
|
+
// Force Node to resolve to look for the nx binary that is inside node_modules
|
163
|
+
const nxBin = require.resolve('nx/bin/nx');
|
164
|
+
// Get the remotes from the module federation config
|
165
|
+
const p = context.projectsConfigurations.projects[context.projectName];
|
166
|
+
const options = getBuildAndServeOptionsFromServeTarget(schema.serveTarget, context);
|
167
|
+
const moduleFederationConfig = (0, module_federation_1.getModuleFederationConfig)(options.buildOptions.tsConfig, context.root, p.root, 'react');
|
168
|
+
const remotes = (0, module_federation_1.getRemotes)([], options.serveOptions.skipRemotes, moduleFederationConfig, {
|
169
|
+
projectName: context.projectName,
|
170
|
+
projectGraph: context.projectGraph,
|
171
|
+
root: context.root,
|
172
|
+
}, options.pathToManifestFile);
|
173
|
+
const staticRemotesConfig = (0, parse_static_remotes_config_1.parseStaticRemotesConfig)([...remotes.staticRemotes, ...remotes.dynamicRemotes], context);
|
174
|
+
options.serveOptions.staticRemotesPort ??= remotes.staticRemotePort;
|
175
|
+
const mappedLocationsOfStaticRemotes = await (0, build_static_remotes_1.buildStaticRemotes)(staticRemotesConfig, nxBin, context, options.serveOptions);
|
176
|
+
// Build the host
|
177
|
+
const hostUrlSegment = (0, path_1.basename)(options.buildOptions.outputPath);
|
178
|
+
const mappedLocationOfHost = `http${options.serveOptions.ssl ? 's' : ''}://${options.serveOptions.host}:${options.serveOptions.staticRemotesPort}/${hostUrlSegment}`;
|
179
|
+
await buildHost(nxBin, options.buildTarget, context);
|
180
|
+
// Move to a temporary directory
|
181
|
+
const commonOutputDirectory = moveToTmpDirectory(staticRemotesConfig, options.buildOptions.outputPath, hostUrlSegment);
|
182
|
+
// File Serve the temporary directory
|
183
|
+
const staticFileServerIter = (0, file_server_impl_1.default)({
|
184
|
+
cors: true,
|
185
|
+
watch: false,
|
186
|
+
staticFilePath: commonOutputDirectory,
|
187
|
+
parallel: false,
|
188
|
+
spa: false,
|
189
|
+
withDeps: false,
|
190
|
+
host: options.serveOptions.host,
|
191
|
+
port: options.serveOptions.staticRemotesPort,
|
192
|
+
ssl: options.serveOptions.ssl,
|
193
|
+
sslCert: options.serveOptions.sslCert,
|
194
|
+
sslKey: options.serveOptions.sslKey,
|
195
|
+
cacheSeconds: -1,
|
196
|
+
}, context);
|
197
|
+
// express proxy all of it
|
198
|
+
startProxies(staticRemotesConfig, options.serveOptions, mappedLocationOfHost, mappedLocationsOfStaticRemotes, options.serveOptions.ssl
|
199
|
+
? {
|
200
|
+
pathToCert: (0, path_1.join)(devkit_1.workspaceRoot, options.serveOptions.sslCert),
|
201
|
+
pathToKey: (0, path_1.join)(devkit_1.workspaceRoot, options.serveOptions.sslKey),
|
202
|
+
}
|
203
|
+
: undefined);
|
204
|
+
return yield* (0, async_iterable_1.combineAsyncIterables)(staticFileServerIter, (0, async_iterable_1.createAsyncIterable)(async ({ next, done }) => {
|
205
|
+
const host = options.serveOptions.host ?? 'localhost';
|
206
|
+
const baseUrl = `http${options.serveOptions.ssl ? 's' : ''}://${host}:${options.serveOptions.port}`;
|
207
|
+
if (remotes.remotePorts.length === 0) {
|
208
|
+
const portsToWaitFor = [options.serveOptions.staticRemotesPort];
|
209
|
+
await Promise.all(portsToWaitFor.map((port) => (0, wait_for_port_open_1.waitForPortOpen)(port, {
|
210
|
+
retries: 480,
|
211
|
+
retryDelay: 2500,
|
212
|
+
host: host,
|
213
|
+
})));
|
214
|
+
devkit_1.logger.info(`NX Server ready at ${baseUrl}`);
|
215
|
+
next({ success: true, baseUrl: baseUrl });
|
216
|
+
done();
|
217
|
+
return;
|
218
|
+
}
|
219
|
+
try {
|
220
|
+
const portsToWaitFor = staticFileServerIter
|
221
|
+
? [options.serveOptions.staticRemotesPort, ...remotes.remotePorts]
|
222
|
+
: [...remotes.remotePorts];
|
223
|
+
await Promise.all(portsToWaitFor.map((port) => (0, wait_for_port_open_1.waitForPortOpen)(port, {
|
224
|
+
retries: 480,
|
225
|
+
retryDelay: 2500,
|
226
|
+
host: host,
|
227
|
+
})));
|
228
|
+
devkit_1.logger.info(`NX Server ready at ${baseUrl}`);
|
229
|
+
next({ success: true, baseUrl: baseUrl });
|
230
|
+
}
|
231
|
+
catch (err) {
|
232
|
+
throw new Error(`Failed to start. Check above for any errors.`, {
|
233
|
+
cause: err,
|
234
|
+
});
|
235
|
+
}
|
236
|
+
finally {
|
237
|
+
done();
|
238
|
+
}
|
239
|
+
}));
|
240
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
{
|
2
|
+
"version": 2,
|
3
|
+
"outputCapture": "direct-nodejs",
|
4
|
+
"title": "Module Federation Static Dev Server",
|
5
|
+
"description": "Serve a host application statically along with it's remotes.",
|
6
|
+
"cli": "nx",
|
7
|
+
"type": "object",
|
8
|
+
"properties": {
|
9
|
+
"serveTarget": {
|
10
|
+
"type": "string"
|
11
|
+
}
|
12
|
+
},
|
13
|
+
"required": ["serveTarget"]
|
14
|
+
}
|
@@ -153,7 +153,10 @@ async function applicationGeneratorInternal(host, schema) {
|
|
153
153
|
const { configurationGenerator } = (0, devkit_1.ensurePackage)('@nx/rspack', versions_1.nxRspackVersion);
|
154
154
|
const rspackTask = await configurationGenerator(host, {
|
155
155
|
project: options.projectName,
|
156
|
-
main: (0, devkit_1.joinPathFragments)(options.appProjectRoot, (0, maybe_js_1.maybeJs)(
|
156
|
+
main: (0, devkit_1.joinPathFragments)(options.appProjectRoot, (0, maybe_js_1.maybeJs)({
|
157
|
+
js: options.js,
|
158
|
+
useJsx: true,
|
159
|
+
}, `src/main.tsx`)),
|
157
160
|
tsConfig: (0, devkit_1.joinPathFragments)(options.appProjectRoot, 'tsconfig.app.json'),
|
158
161
|
target: 'web',
|
159
162
|
newProject: true,
|
@@ -14,7 +14,10 @@ function addRouting(host, options) {
|
|
14
14
|
if (!tsModule) {
|
15
15
|
tsModule = (0, ensure_typescript_1.ensureTypescript)();
|
16
16
|
}
|
17
|
-
const appPath = (0, devkit_1.joinPathFragments)(options.appProjectRoot, (0, maybe_js_1.maybeJs)(
|
17
|
+
const appPath = (0, devkit_1.joinPathFragments)(options.appProjectRoot, (0, maybe_js_1.maybeJs)({
|
18
|
+
js: options.js,
|
19
|
+
useJsx: options.bundler === 'vite' || options.bundler === 'rspack',
|
20
|
+
}, `src/app/${options.fileName}.tsx`));
|
18
21
|
const appFileContent = host.read(appPath, 'utf-8');
|
19
22
|
const appSource = tsModule.createSourceFile(appPath, appFileContent, tsModule.ScriptTarget.Latest, true);
|
20
23
|
const changes = (0, devkit_1.applyChangesToString)(appFileContent, (0, ast_utils_1.addInitialRoutes)(appPath, appSource));
|
@@ -126,7 +126,7 @@ async function createApplicationFiles(host, options) {
|
|
126
126
|
(0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, styleSolutionSpecificAppFiles), options.appProjectRoot, templateVariables);
|
127
127
|
if (options.js) {
|
128
128
|
(0, devkit_1.toJS)(host, {
|
129
|
-
useJsx: options.bundler === 'vite',
|
129
|
+
useJsx: options.bundler === 'vite' || options.bundler === 'rspack',
|
130
130
|
});
|
131
131
|
}
|
132
132
|
(0, create_ts_config_1.createTsConfig)(host, options.appProjectRoot, 'app', options, relativePathToRootTsConfig);
|
@@ -140,7 +140,10 @@ function createNxWebpackPluginOptions(options) {
|
|
140
140
|
: options.projectName),
|
141
141
|
index: './src/index.html',
|
142
142
|
baseHref: '/',
|
143
|
-
main: (0, maybe_js_1.maybeJs)(
|
143
|
+
main: (0, maybe_js_1.maybeJs)({
|
144
|
+
js: options.js,
|
145
|
+
useJsx: options.bundler === 'vite' || options.bundler === 'rspack',
|
146
|
+
}, `./src/main.tsx`),
|
144
147
|
tsConfig: './tsconfig.app.json',
|
145
148
|
assets: ['./src/favicon.ico', './src/assets'],
|
146
149
|
styles: options.styledModule || !options.hasStyles
|
@@ -29,6 +29,7 @@ async function federateModuleGenerator(tree, schema) {
|
|
29
29
|
unitTestRunner: schema.unitTestRunner,
|
30
30
|
host: schema.host,
|
31
31
|
projectNameAndRootFormat: schema.projectNameAndRootFormat ?? 'derived',
|
32
|
+
bundler: schema.bundler ?? 'rspack',
|
32
33
|
});
|
33
34
|
tasks.push(remoteGenerator);
|
34
35
|
const { projectName, projectRoot: remoteRoot } = await (0, project_name_and_root_utils_1.determineProjectNameAndRootOptions)(tree, {
|
@@ -46,7 +47,10 @@ async function federateModuleGenerator(tree, schema) {
|
|
46
47
|
remoteName = remote.name;
|
47
48
|
}
|
48
49
|
// add path to exposes property
|
49
|
-
|
50
|
+
const normalizedModulePath = schema.bundler === 'rspack'
|
51
|
+
? (0, devkit_1.joinPathFragments)((0, devkit_1.offsetFromRoot)(projectRoot), schema.path)
|
52
|
+
: schema.path;
|
53
|
+
(0, utils_1.addPathToExposes)(tree, projectRoot, schema.name, normalizedModulePath);
|
50
54
|
// Add new path to tsconfig
|
51
55
|
const rootJSON = (0, devkit_1.readJson)(tree, (0, js_1.getRootTsConfigPathInTree)(tree));
|
52
56
|
if (!rootJSON?.compilerOptions?.paths[`${remoteName}/${schema.name}`]) {
|
@@ -76,6 +76,12 @@
|
|
76
76
|
"host": {
|
77
77
|
"type": "string",
|
78
78
|
"description": "The host / shell application for this remote."
|
79
|
+
},
|
80
|
+
"bundler": {
|
81
|
+
"description": "The bundler to use.",
|
82
|
+
"type": "string",
|
83
|
+
"enum": ["rspack", "webpack"],
|
84
|
+
"default": "rspack"
|
79
85
|
}
|
80
86
|
},
|
81
87
|
"required": ["name", "path", "remote"],
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import * as React from 'react';
|
2
|
+
<% if (!minimal) { %>
|
3
|
+
import NxWelcome from "./nx-welcome";
|
4
|
+
<% } %>
|
5
|
+
import { Link, Route, Routes } from 'react-router-dom';
|
6
|
+
|
7
|
+
<% if (remotes.length > 0) { %>
|
8
|
+
<% remotes.forEach(function(r) { %>
|
9
|
+
const <%= r.className %> = React.lazy(() => import('<%= r.fileName %>/Module'));
|
10
|
+
<% }); %>
|
11
|
+
<% } %>
|
12
|
+
export function App() {
|
13
|
+
return (
|
14
|
+
<React.Suspense fallback={null}>
|
15
|
+
<ul>
|
16
|
+
<li><Link to="/">Home</Link></li>
|
17
|
+
<% remotes.forEach(function(r) { %>
|
18
|
+
<li><Link to="/<%=r.fileName%>"><%=r.className%></Link></li>
|
19
|
+
<% }); %>
|
20
|
+
</ul>
|
21
|
+
<Routes>
|
22
|
+
<% if (!minimal) { %>
|
23
|
+
<Route path="/" element={<NxWelcome title="<%= projectName %>"/>} />
|
24
|
+
<% } %>
|
25
|
+
<% remotes.forEach(function(r) { %>
|
26
|
+
<Route path="/<%=r.fileName%>" element={<<%= r.className %>/>} />
|
27
|
+
<% }); %>
|
28
|
+
</Routes>
|
29
|
+
</React.Suspense>
|
30
|
+
);
|
31
|
+
}
|
32
|
+
|
33
|
+
export default App;
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<% if (dynamic) { %>
|
2
|
+
import { setRemoteDefinitions } from '@nx/react/mf';
|
3
|
+
|
4
|
+
fetch('/assets/module-federation.manifest.json')
|
5
|
+
.then((res) => res.json())
|
6
|
+
.then(definitions => setRemoteDefinitions(definitions))
|
7
|
+
.then(() => import('./bootstrap').catch(err => console.error(err)));
|
8
|
+
<% } else { %>
|
9
|
+
import('./bootstrap').catch(err => console.error(err));
|
10
|
+
<% } %>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
const { composePlugins, withNx, withReact } = require('@nx/rspack');
|
2
|
+
const { withModuleFederation } = require('@nx/rspack/module-federation');
|
3
|
+
|
4
|
+
const baseConfig = require('./module-federation.config');
|
5
|
+
|
6
|
+
const config = {
|
7
|
+
...baseConfig,
|
8
|
+
};
|
9
|
+
|
10
|
+
// Nx plugins for rspack to build config object from Nx options and context.
|
11
|
+
/**
|
12
|
+
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support for Module Federation
|
13
|
+
* The DTS Plugin can be enabled by setting dts: true
|
14
|
+
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
15
|
+
*/
|
16
|
+
module.exports = composePlugins(withNx(), withReact(), withModuleFederation(config, { dts: false }));
|
@@ -0,0 +1,36 @@
|
|
1
|
+
const { composePlugins, withNx, withReact } = require('@nx/rspack');
|
2
|
+
const { withModuleFederation } = require('@nx/rspack/module-federation');
|
3
|
+
|
4
|
+
const baseConfig = require('./module-federation.config');
|
5
|
+
|
6
|
+
const prodConfig = {
|
7
|
+
...baseConfig,
|
8
|
+
/*
|
9
|
+
* Remote overrides for production.
|
10
|
+
* Each entry is a pair of a unique name and the URL where it is deployed.
|
11
|
+
*
|
12
|
+
* e.g.
|
13
|
+
* remotes: [
|
14
|
+
* ['app1', 'http://app1.example.com'],
|
15
|
+
* ['app2', 'http://app2.example.com'],
|
16
|
+
* ]
|
17
|
+
*
|
18
|
+
* You can also use a full path to the remoteEntry.js file if desired.
|
19
|
+
*
|
20
|
+
* remotes: [
|
21
|
+
* ['app1', 'http://example.com/path/to/app1/remoteEntry.js'],
|
22
|
+
* ['app2', 'http://example.com/path/to/app2/remoteEntry.js'],
|
23
|
+
* ]
|
24
|
+
*/
|
25
|
+
remotes: [
|
26
|
+
<% remotes.forEach(function(r) {%>['<%= r.fileName %>', 'http://localhost:<%= r.port %>/'],<% }); %>
|
27
|
+
],
|
28
|
+
};
|
29
|
+
|
30
|
+
// Nx plugins for rspack to build config object from Nx options and context.
|
31
|
+
/**
|
32
|
+
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support for Module Federation
|
33
|
+
* The DTS Plugin can be enabled by setting dts: true
|
34
|
+
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
35
|
+
*/
|
36
|
+
module.exports = composePlugins(withNx(), withReact(), withModuleFederation(prodConfig, { dts: false }));
|
@@ -0,0 +1,16 @@
|
|
1
|
+
// @ts-check
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @type {import('@nx/rspack/module-federation').ModuleFederationConfig}
|
5
|
+
**/
|
6
|
+
const moduleFederationConfig = {
|
7
|
+
name: '<%= projectName %>',
|
8
|
+
remotes: [
|
9
|
+
<% if (static) {
|
10
|
+
remotes.forEach(function(r) { %> "<%= r.fileName %>", <% });
|
11
|
+
}
|
12
|
+
%>
|
13
|
+
],
|
14
|
+
};
|
15
|
+
|
16
|
+
module.exports = moduleFederationConfig;
|