@nx/react 17.1.2 → 17.2.0-beta.1
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/mf/dynamic-federation.d.ts +4 -0
- package/mf/dynamic-federation.js +75 -0
- package/mf/index.d.ts +1 -0
- package/mf/index.js +7 -0
- package/package.json +6 -6
- package/src/executors/module-federation-dev-server/module-federation-dev-server.impl.d.ts +1 -0
- package/src/executors/module-federation-dev-server/module-federation-dev-server.impl.js +105 -74
- package/src/executors/module-federation-dev-server/schema.json +4 -0
- package/src/generators/application/lib/update-jest-config.js +6 -7
- package/src/generators/host/files/common/src/app/__fileName__.tsx__tmpl__ +8 -0
- package/src/generators/host/files/common/tsconfig.lint.json__tmpl__ +19 -0
- package/src/generators/host/files/module-federation/module-federation.config.js__tmpl__ +17 -2
- package/src/generators/host/files/module-federation/src/main.ts__tmpl__ +10 -1
- package/src/generators/host/files/module-federation-ssr/module-federation.server.config.js__tmpl__ +5 -2
- package/src/generators/host/files/module-federation-ssr-ts/module-federation.server.config.ts__tmpl__ +5 -2
- package/src/generators/host/files/module-federation-ts/module-federation.config.ts__tmpl__ +17 -2
- package/src/generators/host/files/module-federation-ts/src/main.ts__tmpl__ +10 -1
- package/src/generators/host/host.js +6 -0
- package/src/generators/host/lib/add-module-federation-files.d.ts +2 -1
- package/src/generators/host/lib/add-module-federation-files.js +23 -11
- package/src/generators/host/lib/setup-ssr-for-host.js +1 -0
- package/src/generators/host/schema.d.ts +1 -0
- package/src/generators/host/schema.json +5 -0
- package/src/generators/init/init.js +2 -2
- package/src/generators/remote/files/module-federation/module-federation.config.js__tmpl__ +3 -0
- package/src/generators/remote/files/module-federation-ssr-ts/tsconfig.lint.json__tmpl__ +19 -0
- package/src/generators/remote/files/module-federation-ts/module-federation.config.ts__tmpl__ +3 -0
- package/src/generators/remote/files/module-federation-ts/tsconfig.lint.json__tmpl__ +19 -0
- package/src/generators/remote/lib/add-remote-to-dynamic-host.d.ts +2 -0
- package/src/generators/remote/lib/add-remote-to-dynamic-host.js +11 -0
- package/src/generators/remote/remote.js +10 -0
- package/src/generators/remote/schema.d.ts +1 -0
- package/src/generators/remote/schema.json +6 -0
- package/src/module-federation/utils.js +7 -0
- package/src/rules/update-module-federation-project.d.ts +1 -0
- package/src/rules/update-module-federation-project.js +8 -0
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type ResolveRemoteUrlFunction = (remoteName: string) => string | Promise<string>;
|
|
2
|
+
export declare function setRemoteUrlResolver(_resolveRemoteUrl: ResolveRemoteUrlFunction): void;
|
|
3
|
+
export declare function setRemoteDefinitions(definitions: Record<string, string>): void;
|
|
4
|
+
export declare function loadRemoteModule(remoteName: string, moduleName: string): Promise<any>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadRemoteModule = exports.setRemoteDefinitions = exports.setRemoteUrlResolver = void 0;
|
|
4
|
+
let remoteUrlDefinitions;
|
|
5
|
+
let resolveRemoteUrl;
|
|
6
|
+
const remoteModuleMap = new Map();
|
|
7
|
+
const remoteContainerMap = new Map();
|
|
8
|
+
let initialSharingScopeCreated = false;
|
|
9
|
+
function setRemoteUrlResolver(_resolveRemoteUrl) {
|
|
10
|
+
resolveRemoteUrl = _resolveRemoteUrl;
|
|
11
|
+
}
|
|
12
|
+
exports.setRemoteUrlResolver = setRemoteUrlResolver;
|
|
13
|
+
function setRemoteDefinitions(definitions) {
|
|
14
|
+
remoteUrlDefinitions = definitions;
|
|
15
|
+
}
|
|
16
|
+
exports.setRemoteDefinitions = setRemoteDefinitions;
|
|
17
|
+
async function loadRemoteModule(remoteName, moduleName) {
|
|
18
|
+
const remoteModuleKey = `${remoteName}:${moduleName}`;
|
|
19
|
+
if (remoteModuleMap.has(remoteModuleKey)) {
|
|
20
|
+
return remoteModuleMap.get(remoteModuleKey);
|
|
21
|
+
}
|
|
22
|
+
const container = remoteContainerMap.has(remoteName)
|
|
23
|
+
? remoteContainerMap.get(remoteName)
|
|
24
|
+
: await loadRemoteContainer(remoteName);
|
|
25
|
+
const factory = await container.get(moduleName);
|
|
26
|
+
const Module = factory();
|
|
27
|
+
remoteModuleMap.set(remoteModuleKey, Module);
|
|
28
|
+
return Module;
|
|
29
|
+
}
|
|
30
|
+
exports.loadRemoteModule = loadRemoteModule;
|
|
31
|
+
const fetchRemoteModule = (url, remoteName) => {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const script = document.createElement('script');
|
|
34
|
+
script.src = url;
|
|
35
|
+
script.type = 'text/javascript';
|
|
36
|
+
script.async = true;
|
|
37
|
+
script.onload = () => {
|
|
38
|
+
const proxy = {
|
|
39
|
+
get: (request) => window[remoteName].get(request),
|
|
40
|
+
init: (arg) => {
|
|
41
|
+
try {
|
|
42
|
+
window[remoteName].init(arg);
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
console.error(`Failed to initialize remote ${remoteName}`, e);
|
|
46
|
+
reject(e);
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
resolve(proxy);
|
|
51
|
+
};
|
|
52
|
+
script.onerror = () => reject(new Error(`Remote ${remoteName} not found`));
|
|
53
|
+
document.head.appendChild(script);
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
async function loadRemoteContainer(remoteName) {
|
|
57
|
+
if (!resolveRemoteUrl && !remoteUrlDefinitions) {
|
|
58
|
+
throw new Error('Call setRemoteDefinitions or setRemoteUrlResolver to allow Dynamic Federation to find the remote apps correctly.');
|
|
59
|
+
}
|
|
60
|
+
if (!initialSharingScopeCreated) {
|
|
61
|
+
initialSharingScopeCreated = true;
|
|
62
|
+
await __webpack_init_sharing__('default');
|
|
63
|
+
}
|
|
64
|
+
const remoteUrl = remoteUrlDefinitions
|
|
65
|
+
? remoteUrlDefinitions[remoteName]
|
|
66
|
+
: await resolveRemoteUrl(remoteName);
|
|
67
|
+
let containerUrl = remoteUrl;
|
|
68
|
+
if (!remoteUrl.endsWith('.mjs') && !remoteUrl.endsWith('.js')) {
|
|
69
|
+
containerUrl = `${remoteUrl}${remoteUrl.endsWith('/') ? '' : '/'}remoteEntry.js`;
|
|
70
|
+
}
|
|
71
|
+
const container = await fetchRemoteModule(containerUrl, remoteName);
|
|
72
|
+
await container.init(__webpack_share_scopes__.default);
|
|
73
|
+
remoteContainerMap.set(remoteName, container);
|
|
74
|
+
return container;
|
|
75
|
+
}
|
package/mf/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { loadRemoteModule, setRemoteDefinitions, setRemoteUrlResolver, } from './dynamic-federation';
|
package/mf/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setRemoteUrlResolver = exports.setRemoteDefinitions = exports.loadRemoteModule = void 0;
|
|
4
|
+
var dynamic_federation_1 = require("./dynamic-federation");
|
|
5
|
+
Object.defineProperty(exports, "loadRemoteModule", { enumerable: true, get: function () { return dynamic_federation_1.loadRemoteModule; } });
|
|
6
|
+
Object.defineProperty(exports, "setRemoteDefinitions", { enumerable: true, get: function () { return dynamic_federation_1.setRemoteDefinitions; } });
|
|
7
|
+
Object.defineProperty(exports, "setRemoteUrlResolver", { enumerable: true, get: function () { return dynamic_federation_1.setRemoteUrlResolver; } });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/react",
|
|
3
|
-
"version": "17.1
|
|
3
|
+
"version": "17.2.0-beta.1",
|
|
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, 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": {
|
|
@@ -37,11 +37,11 @@
|
|
|
37
37
|
"file-loader": "^6.2.0",
|
|
38
38
|
"minimatch": "3.0.5",
|
|
39
39
|
"tslib": "^2.3.0",
|
|
40
|
-
"@nx/devkit": "17.1
|
|
41
|
-
"@nx/js": "17.1
|
|
42
|
-
"@nx/eslint": "17.1
|
|
43
|
-
"@nx/web": "17.1
|
|
44
|
-
"@nrwl/react": "17.1
|
|
40
|
+
"@nx/devkit": "17.2.0-beta.1",
|
|
41
|
+
"@nx/js": "17.2.0-beta.1",
|
|
42
|
+
"@nx/eslint": "17.2.0-beta.1",
|
|
43
|
+
"@nx/web": "17.2.0-beta.1",
|
|
44
|
+
"@nrwl/react": "17.2.0-beta.1"
|
|
45
45
|
},
|
|
46
46
|
"publishConfig": {
|
|
47
47
|
"access": "public"
|
|
@@ -6,6 +6,7 @@ type ModuleFederationDevServerOptions = WebDevServerOptions & {
|
|
|
6
6
|
static?: boolean;
|
|
7
7
|
isInitialHost?: boolean;
|
|
8
8
|
parallel?: number;
|
|
9
|
+
staticRemotesPort?: number;
|
|
9
10
|
};
|
|
10
11
|
export default function moduleFederationDevServer(options: ModuleFederationDevServerOptions, context: ExecutorContext): AsyncIterableIterator<{
|
|
11
12
|
success: boolean;
|
|
@@ -7,6 +7,8 @@ const module_federation_1 = require("@nx/webpack/src/utils/module-federation");
|
|
|
7
7
|
const async_iterable_1 = require("@nx/devkit/src/utils/async-iterable");
|
|
8
8
|
const wait_for_port_open_1 = require("@nx/web/src/utils/wait-for-port-open");
|
|
9
9
|
const child_process_1 = require("child_process");
|
|
10
|
+
const path_1 = require("path");
|
|
11
|
+
const fs_1 = require("fs");
|
|
10
12
|
function getBuildOptions(buildTarget, context) {
|
|
11
13
|
const target = (0, devkit_1.parseTargetString)(buildTarget, context);
|
|
12
14
|
const buildOptions = (0, devkit_1.readTargetOptions)(target, context);
|
|
@@ -14,62 +16,46 @@ function getBuildOptions(buildTarget, context) {
|
|
|
14
16
|
...buildOptions,
|
|
15
17
|
};
|
|
16
18
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const p = context.projectsConfigurations.projects[context.projectName];
|
|
30
|
-
const buildOptions = getBuildOptions(options.buildTarget, context);
|
|
31
|
-
if (!options.isInitialHost) {
|
|
32
|
-
return yield* currIter;
|
|
19
|
+
function startStaticRemotesFileServer(remotes, context, options) {
|
|
20
|
+
let shouldMoveToCommonLocation = false;
|
|
21
|
+
let commonOutputDirectory;
|
|
22
|
+
for (const app of remotes.staticRemotes) {
|
|
23
|
+
const outputPath = context.projectGraph.nodes[app].data.targets['build'].options.outputPath;
|
|
24
|
+
const directoryOfOutputPath = (0, path_1.dirname)(outputPath);
|
|
25
|
+
if (!commonOutputDirectory) {
|
|
26
|
+
commonOutputDirectory = directoryOfOutputPath;
|
|
27
|
+
}
|
|
28
|
+
else if (commonOutputDirectory !== directoryOfOutputPath) {
|
|
29
|
+
shouldMoveToCommonLocation = true;
|
|
30
|
+
}
|
|
33
31
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
staticProcess.stderr.on('data', (data) => devkit_1.logger.info(data.toString()));
|
|
64
|
-
staticProcess.on('exit', (code) => {
|
|
65
|
-
if (code !== 0) {
|
|
66
|
-
throw new Error(`Remote failed to start. See above for errors.`);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
process.on('SIGTERM', () => staticProcess.kill('SIGTERM'));
|
|
70
|
-
process.on('exit', () => staticProcess.kill('SIGTERM'));
|
|
71
|
-
});
|
|
72
|
-
let isCollectingStaticRemoteOutput = true;
|
|
32
|
+
if (shouldMoveToCommonLocation) {
|
|
33
|
+
commonOutputDirectory = (0, path_1.join)(devkit_1.workspaceRoot, 'tmp/static-remotes');
|
|
34
|
+
for (const app of remotes.staticRemotes) {
|
|
35
|
+
const outputPath = context.projectGraph.nodes[app].data.targets['build'].options
|
|
36
|
+
.outputPath;
|
|
37
|
+
(0, fs_1.cpSync)(outputPath, commonOutputDirectory, {
|
|
38
|
+
force: true,
|
|
39
|
+
recursive: true,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const staticRemotesIter = (0, file_server_impl_1.default)({
|
|
44
|
+
cors: true,
|
|
45
|
+
watch: false,
|
|
46
|
+
staticFilePath: commonOutputDirectory,
|
|
47
|
+
parallel: false,
|
|
48
|
+
spa: false,
|
|
49
|
+
withDeps: false,
|
|
50
|
+
host: options.host,
|
|
51
|
+
port: options.staticRemotesPort,
|
|
52
|
+
ssl: options.ssl,
|
|
53
|
+
sslCert: options.sslCert,
|
|
54
|
+
sslKey: options.sslKey,
|
|
55
|
+
}, context);
|
|
56
|
+
return staticRemotesIter;
|
|
57
|
+
}
|
|
58
|
+
async function startDevRemotes(remotes, context) {
|
|
73
59
|
const devRemoteIters = [];
|
|
74
60
|
for (const app of remotes.devRemotes) {
|
|
75
61
|
const remoteProjectServeTarget = context.projectGraph.nodes[app].data.targets['serve'];
|
|
@@ -85,40 +71,86 @@ async function* moduleFederationDevServer(options, context) {
|
|
|
85
71
|
: {}),
|
|
86
72
|
}, context));
|
|
87
73
|
}
|
|
74
|
+
return devRemoteIters;
|
|
75
|
+
}
|
|
76
|
+
async function buildStaticRemotes(remotes, nxBin, context, options) {
|
|
77
|
+
devkit_1.logger.info(`NX Building ${remotes.staticRemotes.length} static remotes...`);
|
|
78
|
+
const mappedLocationOfRemotes = {};
|
|
88
79
|
for (const app of remotes.staticRemotes) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
80
|
+
mappedLocationOfRemotes[app] = `http${options.ssl ? 's' : ''}://${options.host}:${options.staticRemotesPort}/${app}`;
|
|
81
|
+
}
|
|
82
|
+
process.env.NX_MF_DEV_SERVER_STATIC_REMOTES = JSON.stringify(mappedLocationOfRemotes);
|
|
83
|
+
await new Promise((res) => {
|
|
92
84
|
const staticProcess = (0, child_process_1.fork)(nxBin, [
|
|
93
|
-
'run',
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
85
|
+
'run-many',
|
|
86
|
+
`--target=build`,
|
|
87
|
+
`--projects=${remotes.staticRemotes.join(',')}`,
|
|
88
|
+
...(context.configurationName
|
|
89
|
+
? [`--configuration=${context.configurationName}`]
|
|
97
90
|
: []),
|
|
91
|
+
...(options.parallel ? [`--parallel=${options.parallel}`] : []),
|
|
98
92
|
], {
|
|
99
93
|
cwd: context.root,
|
|
100
94
|
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
|
101
95
|
});
|
|
102
96
|
staticProcess.stdout.on('data', (data) => {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
else {
|
|
107
|
-
outWithErr = null;
|
|
97
|
+
const ANSII_CODE_REGEX = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
|
98
|
+
const stdoutString = data.toString().replace(ANSII_CODE_REGEX, '');
|
|
99
|
+
if (stdoutString.includes('Successfully ran target build')) {
|
|
108
100
|
staticProcess.stdout.removeAllListeners('data');
|
|
101
|
+
devkit_1.logger.info(`NX Built ${remotes.staticRemotes.length} static remotes`);
|
|
102
|
+
res();
|
|
109
103
|
}
|
|
110
104
|
});
|
|
111
105
|
staticProcess.stderr.on('data', (data) => devkit_1.logger.info(data.toString()));
|
|
112
106
|
staticProcess.on('exit', (code) => {
|
|
113
107
|
if (code !== 0) {
|
|
114
|
-
devkit_1.logger.info(outWithErr.join(''));
|
|
115
108
|
throw new Error(`Remote failed to start. See above for errors.`);
|
|
116
109
|
}
|
|
117
110
|
});
|
|
118
111
|
process.on('SIGTERM', () => staticProcess.kill('SIGTERM'));
|
|
119
112
|
process.on('exit', () => staticProcess.kill('SIGTERM'));
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async function* moduleFederationDevServer(options, context) {
|
|
116
|
+
const initialStaticRemotesPorts = options.staticRemotesPort;
|
|
117
|
+
options.staticRemotesPort ??= options.port + 1;
|
|
118
|
+
// Force Node to resolve to look for the nx binary that is inside node_modules
|
|
119
|
+
const nxBin = require.resolve('nx/bin/nx');
|
|
120
|
+
const currIter = options.static
|
|
121
|
+
? (0, file_server_impl_1.default)({
|
|
122
|
+
...options,
|
|
123
|
+
parallel: false,
|
|
124
|
+
withDeps: false,
|
|
125
|
+
spa: false,
|
|
126
|
+
cors: true,
|
|
127
|
+
}, context)
|
|
128
|
+
: (0, dev_server_impl_1.default)(options, context);
|
|
129
|
+
const p = context.projectsConfigurations.projects[context.projectName];
|
|
130
|
+
const buildOptions = getBuildOptions(options.buildTarget, context);
|
|
131
|
+
if (!options.isInitialHost) {
|
|
132
|
+
return yield* currIter;
|
|
133
|
+
}
|
|
134
|
+
const moduleFederationConfig = (0, module_federation_1.getModuleFederationConfig)(buildOptions.tsConfig, context.root, p.root, 'react');
|
|
135
|
+
const remotes = (0, module_federation_1.getRemotes)(options.devRemotes, options.skipRemotes, moduleFederationConfig, {
|
|
136
|
+
projectName: context.projectName,
|
|
137
|
+
projectGraph: context.projectGraph,
|
|
138
|
+
root: context.root,
|
|
139
|
+
});
|
|
140
|
+
if (remotes.devRemotes.length > 0 && !initialStaticRemotesPorts) {
|
|
141
|
+
options.staticRemotesPort = options.devRemotes.reduce((portToUse, r) => {
|
|
142
|
+
const remotePort = context.projectGraph.nodes[r].data.targets['serve'].options.port;
|
|
143
|
+
if (remotePort >= portToUse) {
|
|
144
|
+
return remotePort + 1;
|
|
145
|
+
}
|
|
146
|
+
}, options.staticRemotesPort);
|
|
120
147
|
}
|
|
121
|
-
|
|
148
|
+
await buildStaticRemotes(remotes, nxBin, context, options);
|
|
149
|
+
const devRemoteIters = await startDevRemotes(remotes, context);
|
|
150
|
+
const staticRemotesIter = remotes.staticRemotes.length > 0
|
|
151
|
+
? startStaticRemotesFileServer(remotes, context, options)
|
|
152
|
+
: undefined;
|
|
153
|
+
return yield* (0, async_iterable_1.combineAsyncIterables)(currIter, ...devRemoteIters, ...(staticRemotesIter ? [staticRemotesIter] : []), (0, async_iterable_1.createAsyncIterable)(async ({ next, done }) => {
|
|
122
154
|
if (!options.isInitialHost) {
|
|
123
155
|
done();
|
|
124
156
|
return;
|
|
@@ -128,15 +160,14 @@ async function* moduleFederationDevServer(options, context) {
|
|
|
128
160
|
return;
|
|
129
161
|
}
|
|
130
162
|
try {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
(0, wait_for_port_open_1.waitForPortOpen)(port, {
|
|
163
|
+
const portsToWaitFor = staticRemotesIter
|
|
164
|
+
? [options.staticRemotesPort, ...remotes.remotePorts]
|
|
165
|
+
: [...remotes.remotePorts];
|
|
166
|
+
await Promise.all(portsToWaitFor.map((port) => (0, wait_for_port_open_1.waitForPortOpen)(port, {
|
|
135
167
|
retries: 480,
|
|
136
168
|
retryDelay: 2500,
|
|
137
169
|
host: 'localhost',
|
|
138
170
|
})));
|
|
139
|
-
isCollectingStaticRemoteOutput = false;
|
|
140
171
|
devkit_1.logger.info(`NX All remotes started, server ready at http://localhost:${options.port}`);
|
|
141
172
|
next({ success: true, baseUrl: `http://localhost:${options.port}` });
|
|
142
173
|
}
|
|
@@ -105,6 +105,10 @@
|
|
|
105
105
|
"parallel": {
|
|
106
106
|
"type": "number",
|
|
107
107
|
"description": "Max number of parallel processes for building static remotes"
|
|
108
|
+
},
|
|
109
|
+
"staticRemotesPort": {
|
|
110
|
+
"type": "number",
|
|
111
|
+
"description": "The port at which to serve the file-server for the static remotes."
|
|
108
112
|
}
|
|
109
113
|
}
|
|
110
114
|
}
|
|
@@ -8,15 +8,14 @@ function updateSpecConfig(host, options) {
|
|
|
8
8
|
return;
|
|
9
9
|
}
|
|
10
10
|
(0, devkit_1.updateJson)(host, `${options.appProjectRoot}/tsconfig.spec.json`, (json) => {
|
|
11
|
-
|
|
11
|
+
const compilerOptions = json.compilerOptions ?? {};
|
|
12
|
+
const types = compilerOptions.types ?? [];
|
|
12
13
|
if (options.style === 'styled-jsx') {
|
|
13
|
-
|
|
14
|
+
types.push('@nx/react/typings/styled-jsx.d.ts');
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
'@nx/react/typings/image.d.ts',
|
|
19
|
-
];
|
|
16
|
+
types.push('@nx/react/typings/cssmodule.d.ts', '@nx/react/typings/image.d.ts');
|
|
17
|
+
compilerOptions.types = types;
|
|
18
|
+
json.compilerOptions = compilerOptions;
|
|
20
19
|
return json;
|
|
21
20
|
});
|
|
22
21
|
if (options.unitTestRunner !== 'jest') {
|
|
@@ -3,12 +3,20 @@ import * as React from 'react';
|
|
|
3
3
|
import NxWelcome from "./nx-welcome";
|
|
4
4
|
<% } %>
|
|
5
5
|
import { Link, Route, Routes } from 'react-router-dom';
|
|
6
|
+
<% if (dynamic) { %>
|
|
7
|
+
import { loadRemoteModule } from '@nx/react/mf';
|
|
8
|
+
<% } %>
|
|
6
9
|
|
|
7
10
|
<% if (remotes.length > 0) { %>
|
|
8
11
|
<% remotes.forEach(function(r) { %>
|
|
12
|
+
<% if (dynamic) { %>
|
|
13
|
+
const <%= r.className %> = React.lazy(() => loadRemoteModule('<%= r.fileName %>', './Module'))
|
|
14
|
+
<% } else { %>
|
|
9
15
|
const <%= r.className %> = React.lazy(() => import('<%= r.fileName %>/Module'));
|
|
16
|
+
<% } %>
|
|
10
17
|
<% }); %>
|
|
11
18
|
<% } %>
|
|
19
|
+
|
|
12
20
|
export function App() {
|
|
13
21
|
return (
|
|
14
22
|
<React.Suspense fallback={null}>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../dist/out-tsc",
|
|
5
|
+
"types": [
|
|
6
|
+
"node",
|
|
7
|
+
"@nx/react/typings/cssmodule.d.ts",
|
|
8
|
+
"@nx/react/typings/image.d.ts"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
"include": [
|
|
12
|
+
"src/**/*.js",
|
|
13
|
+
"src/**/*.jsx",
|
|
14
|
+
"src/**/*.ts",
|
|
15
|
+
"src/**/*.tsx",
|
|
16
|
+
"webpack.config.ts",
|
|
17
|
+
"webpack.prod.config.ts"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
name: '<%= projectName %>',
|
|
3
|
+
/**
|
|
4
|
+
* To use a remote that does not exist in your current Nx Workspace
|
|
5
|
+
* You can use the tuple-syntax to define your remote
|
|
6
|
+
*
|
|
7
|
+
* remotes: [['my-external-remote', 'https://nx-angular-remote.netlify.app']]
|
|
8
|
+
*
|
|
9
|
+
* You _may_ need to add a `remotes.d.ts` file to your `src/` folder declaring the external remote for tsc, with the
|
|
10
|
+
* following content:
|
|
11
|
+
*
|
|
12
|
+
* declare module 'my-external-remote';
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
3
15
|
remotes: [
|
|
4
|
-
|
|
16
|
+
<% if (static) {
|
|
17
|
+
remotes.forEach(function(r) { %> "<%= r.fileName %>", <% });
|
|
18
|
+
}
|
|
19
|
+
%>
|
|
5
20
|
],
|
|
6
|
-
};
|
|
21
|
+
};
|
|
@@ -1 +1,10 @@
|
|
|
1
|
-
|
|
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
|
+
<% } %>
|
package/src/generators/host/files/module-federation-ssr/module-federation.server.config.js__tmpl__
CHANGED
|
@@ -6,8 +6,11 @@
|
|
|
6
6
|
const moduleFederationConfig = {
|
|
7
7
|
name: '<%= projectName %>',
|
|
8
8
|
remotes: [
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
<% if (static) {
|
|
10
|
+
remotes.forEach(function(r) { %> "<%= r.fileName %>", <% });
|
|
11
|
+
}
|
|
12
|
+
%>
|
|
13
|
+
],
|
|
11
14
|
};
|
|
12
15
|
|
|
13
16
|
module.exports = moduleFederationConfig;
|
|
@@ -3,8 +3,11 @@ import { ModuleFederationConfig } from '@nx/webpack';
|
|
|
3
3
|
const config: ModuleFederationConfig = {
|
|
4
4
|
name: '<%= projectName %>',
|
|
5
5
|
remotes: [
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
<% if (static) {
|
|
7
|
+
remotes.forEach(function(r) { %> "<%= r.fileName %>", <% });
|
|
8
|
+
}
|
|
9
|
+
%>
|
|
10
|
+
],
|
|
8
11
|
};
|
|
9
12
|
|
|
10
13
|
export default config;
|
|
@@ -2,9 +2,24 @@ import { ModuleFederationConfig } from '@nx/webpack';
|
|
|
2
2
|
|
|
3
3
|
const config: ModuleFederationConfig = {
|
|
4
4
|
name: '<%= projectName %>',
|
|
5
|
+
/**
|
|
6
|
+
* To use a remote that does not exist in your current Nx Workspace
|
|
7
|
+
* You can use the tuple-syntax to define your remote
|
|
8
|
+
*
|
|
9
|
+
* remotes: [['my-external-remote', 'https://nx-angular-remote.netlify.app']]
|
|
10
|
+
*
|
|
11
|
+
* You _may_ need to add a `remotes.d.ts` file to your `src/` folder declaring the external remote for tsc, with the
|
|
12
|
+
* following content:
|
|
13
|
+
*
|
|
14
|
+
* declare module 'my-external-remote';
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
5
17
|
remotes: [
|
|
6
|
-
|
|
7
|
-
|
|
18
|
+
<% if (static) {
|
|
19
|
+
remotes.forEach(function(r) { %> "<%= r.fileName %>", <% });
|
|
20
|
+
}
|
|
21
|
+
%>
|
|
22
|
+
],
|
|
8
23
|
};
|
|
9
24
|
|
|
10
25
|
export default config;
|
|
@@ -1 +1,10 @@
|
|
|
1
|
-
|
|
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
|
+
<% } %>
|
|
@@ -23,6 +23,7 @@ async function hostGeneratorInternal(host, schema) {
|
|
|
23
23
|
const options = {
|
|
24
24
|
...(await (0, normalize_options_1.normalizeOptions)(host, schema, '@nx/react:host')),
|
|
25
25
|
typescriptConfiguration: schema.typescriptConfiguration ?? true,
|
|
26
|
+
dynamic: schema.dynamic ?? false,
|
|
26
27
|
};
|
|
27
28
|
const initTask = await (0, application_1.default)(host, {
|
|
28
29
|
...options,
|
|
@@ -51,6 +52,8 @@ async function hostGeneratorInternal(host, schema) {
|
|
|
51
52
|
skipFormat: true,
|
|
52
53
|
projectNameAndRootFormat: options.projectNameAndRootFormat,
|
|
53
54
|
typescriptConfiguration: options.typescriptConfiguration,
|
|
55
|
+
dynamic: options.dynamic,
|
|
56
|
+
host: options.name,
|
|
54
57
|
});
|
|
55
58
|
tasks.push(remoteTask);
|
|
56
59
|
remotePort++;
|
|
@@ -72,6 +75,9 @@ async function hostGeneratorInternal(host, schema) {
|
|
|
72
75
|
projectConfig.targets.server.options.webpackConfig = (0, devkit_1.joinPathFragments)(projectConfig.root, `webpack.server.config.${options.typescriptConfiguration ? 'ts' : 'js'}`);
|
|
73
76
|
(0, devkit_1.updateProjectConfiguration)(host, options.projectName, projectConfig);
|
|
74
77
|
}
|
|
78
|
+
if (!options.setParserOptionsProject) {
|
|
79
|
+
host.delete((0, devkit_1.joinPathFragments)(options.appProjectRoot, 'tsconfig.lint.json'));
|
|
80
|
+
}
|
|
75
81
|
if (!options.skipFormat) {
|
|
76
82
|
await (0, devkit_1.formatFiles)(host);
|
|
77
83
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NormalizedSchema } from '../schema';
|
|
2
|
-
|
|
2
|
+
import { Tree } from '@nx/devkit';
|
|
3
|
+
export declare function addModuleFederationFiles(host: Tree, options: NormalizedSchema, defaultRemoteManifest: {
|
|
3
4
|
name: string;
|
|
4
5
|
port: number;
|
|
5
6
|
}[]): void;
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.addModuleFederationFiles = void 0;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
|
-
const path_1 = require("path");
|
|
6
5
|
function addModuleFederationFiles(host, options, defaultRemoteManifest) {
|
|
7
6
|
const templateVariables = {
|
|
8
7
|
...(0, devkit_1.names)(options.name),
|
|
9
8
|
...options,
|
|
9
|
+
static: !options?.dynamic,
|
|
10
10
|
tmpl: '',
|
|
11
11
|
remotes: defaultRemoteManifest.map(({ name, port }) => {
|
|
12
12
|
return {
|
|
@@ -15,24 +15,36 @@ function addModuleFederationFiles(host, options, defaultRemoteManifest) {
|
|
|
15
15
|
};
|
|
16
16
|
}),
|
|
17
17
|
};
|
|
18
|
+
const projectConfig = (0, devkit_1.readProjectConfiguration)(host, options.name);
|
|
19
|
+
const pathToMFManifest = (0, devkit_1.joinPathFragments)(projectConfig.sourceRoot, 'assets/module-federation.manifest.json');
|
|
18
20
|
// Module federation requires bootstrap code to be dynamically imported.
|
|
19
21
|
// Renaming original entry file so we can use `import(./bootstrap)` in
|
|
20
22
|
// new entry file.
|
|
21
|
-
host.rename((0,
|
|
22
|
-
(0, devkit_1.generateFiles)(host, (0,
|
|
23
|
+
host.rename((0, devkit_1.joinPathFragments)(options.appProjectRoot, 'src/main.tsx'), (0, devkit_1.joinPathFragments)(options.appProjectRoot, 'src/bootstrap.tsx'));
|
|
24
|
+
(0, devkit_1.generateFiles)(host, (0, devkit_1.joinPathFragments)(__dirname, `../files/common`), options.appProjectRoot, templateVariables);
|
|
23
25
|
const pathToModuleFederationFiles = options.typescriptConfiguration
|
|
24
26
|
? 'module-federation-ts'
|
|
25
27
|
: 'module-federation';
|
|
26
28
|
// New entry file is created here.
|
|
27
|
-
(0, devkit_1.generateFiles)(host, (0,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (host.exists(pathToWebpackConfig)) {
|
|
32
|
-
host.delete(pathToWebpackConfig);
|
|
29
|
+
(0, devkit_1.generateFiles)(host, (0, devkit_1.joinPathFragments)(__dirname, `../files/${pathToModuleFederationFiles}`), options.appProjectRoot, templateVariables);
|
|
30
|
+
function deleteFileIfExists(host, filePath) {
|
|
31
|
+
if (host.exists(filePath)) {
|
|
32
|
+
host.delete(filePath);
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
}
|
|
35
|
+
function processWebpackConfig(options, host, fileName) {
|
|
36
|
+
const pathToWebpackConfig = (0, devkit_1.joinPathFragments)(options.appProjectRoot, fileName);
|
|
37
|
+
deleteFileIfExists(host, pathToWebpackConfig);
|
|
38
|
+
}
|
|
39
|
+
if (options.typescriptConfiguration) {
|
|
40
|
+
processWebpackConfig(options, host, 'webpack.config.js');
|
|
41
|
+
processWebpackConfig(options, host, 'webpack.config.prod.js');
|
|
42
|
+
}
|
|
43
|
+
if (options.dynamic) {
|
|
44
|
+
processWebpackConfig(options, host, 'webpack.config.prod.js');
|
|
45
|
+
processWebpackConfig(options, host, 'webpack.config.prod.ts');
|
|
46
|
+
if (!host.exists(pathToMFManifest)) {
|
|
47
|
+
host.write(pathToMFManifest, '{}');
|
|
36
48
|
}
|
|
37
49
|
}
|
|
38
50
|
}
|
|
@@ -13,6 +13,7 @@ async function setupSsrForHost(tree, options, appName, defaultRemoteManifest) {
|
|
|
13
13
|
: 'module-federation-ssr';
|
|
14
14
|
(0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, `../files/${pathToModuleFederationSsrFiles}`), project.root, {
|
|
15
15
|
...options,
|
|
16
|
+
static: !options?.dynamic,
|
|
16
17
|
remotes: defaultRemoteManifest.map(({ name, port }) => {
|
|
17
18
|
return {
|
|
18
19
|
...(0, devkit_1.names)(name),
|
|
@@ -74,6 +74,11 @@
|
|
|
74
74
|
"enum": ["eslint"],
|
|
75
75
|
"default": "eslint"
|
|
76
76
|
},
|
|
77
|
+
"dynamic": {
|
|
78
|
+
"type": "boolean",
|
|
79
|
+
"description": "Should the host application use dynamic federation?",
|
|
80
|
+
"default": false
|
|
81
|
+
},
|
|
77
82
|
"skipFormat": {
|
|
78
83
|
"description": "Skip formatting files.",
|
|
79
84
|
"type": "boolean",
|
|
@@ -48,8 +48,8 @@ async function reactInitGenerator(host, schema) {
|
|
|
48
48
|
setDefault(host);
|
|
49
49
|
if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') {
|
|
50
50
|
(0, devkit_1.ensurePackage)('@nx/cypress', versions_1.nxVersion);
|
|
51
|
-
const { cypressInitGenerator } = await Promise.resolve().then(() => require('@nx/cypress/src/generators/init/init'));
|
|
52
|
-
const cypressTask = await cypressInitGenerator(host,
|
|
51
|
+
const { cypressInitGenerator } = (await Promise.resolve().then(() => require('@nx/cypress/src/generators/init/init')));
|
|
52
|
+
const cypressTask = await cypressInitGenerator(host, schema);
|
|
53
53
|
tasks.push(cypressTask);
|
|
54
54
|
}
|
|
55
55
|
if (!schema.skipPackageJson) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../dist/out-tsc",
|
|
5
|
+
"types": [
|
|
6
|
+
"node",
|
|
7
|
+
"@nx/react/typings/cssmodule.d.ts",
|
|
8
|
+
"@nx/react/typings/image.d.ts"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
"include": [
|
|
12
|
+
"src/**/*.js",
|
|
13
|
+
"src/**/*.jsx",
|
|
14
|
+
"src/**/*.ts",
|
|
15
|
+
"src/**/*.tsx",
|
|
16
|
+
"webpack.config.ts",
|
|
17
|
+
"webpack.prod.config.ts"
|
|
18
|
+
]
|
|
19
|
+
}
|
package/src/generators/remote/files/module-federation-ts/module-federation.config.ts__tmpl__
CHANGED
|
@@ -2,6 +2,9 @@ import {ModuleFederationConfig} from '@nx/webpack';
|
|
|
2
2
|
|
|
3
3
|
const config: ModuleFederationConfig = {
|
|
4
4
|
name: '<%= projectName %>',
|
|
5
|
+
<% if (dynamic) { %>
|
|
6
|
+
library: { type: 'var', name: '<%= projectName %>'},
|
|
7
|
+
<% } %>
|
|
5
8
|
exposes: {
|
|
6
9
|
'./Module': './src/remote-entry.ts',
|
|
7
10
|
},
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../dist/out-tsc",
|
|
5
|
+
"types": [
|
|
6
|
+
"node",
|
|
7
|
+
"@nx/react/typings/cssmodule.d.ts",
|
|
8
|
+
"@nx/react/typings/image.d.ts"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
"include": [
|
|
12
|
+
"src/**/*.js",
|
|
13
|
+
"src/**/*.jsx",
|
|
14
|
+
"src/**/*.ts",
|
|
15
|
+
"src/**/*.tsx",
|
|
16
|
+
"webpack.config.ts",
|
|
17
|
+
"webpack.prod.config.ts"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addRemoteToDynamicHost = void 0;
|
|
4
|
+
function addRemoteToDynamicHost(tree, remoteName, remotePort, pathToMfManifest) {
|
|
5
|
+
const current = tree.read(pathToMfManifest, 'utf8');
|
|
6
|
+
tree.write(pathToMfManifest, JSON.stringify({
|
|
7
|
+
...JSON.parse(current),
|
|
8
|
+
[remoteName]: `http://localhost:${remotePort}`,
|
|
9
|
+
}));
|
|
10
|
+
}
|
|
11
|
+
exports.addRemoteToDynamicHost = addRemoteToDynamicHost;
|
|
@@ -10,6 +10,7 @@ const update_module_federation_project_1 = require("../../rules/update-module-fe
|
|
|
10
10
|
const setup_ssr_1 = require("../setup-ssr/setup-ssr");
|
|
11
11
|
const setup_ssr_for_remote_1 = require("./lib/setup-ssr-for-remote");
|
|
12
12
|
const setup_tspath_for_remote_1 = require("./lib/setup-tspath-for-remote");
|
|
13
|
+
const add_remote_to_dynamic_host_1 = require("./lib/add-remote-to-dynamic-host");
|
|
13
14
|
function addModuleFederationFiles(host, options) {
|
|
14
15
|
const templateVariables = {
|
|
15
16
|
...(0, devkit_1.names)(options.name),
|
|
@@ -44,6 +45,7 @@ async function remoteGeneratorInternal(host, schema) {
|
|
|
44
45
|
const options = {
|
|
45
46
|
...(await (0, normalize_options_1.normalizeOptions)(host, schema, '@nx/react:remote')),
|
|
46
47
|
typescriptConfiguration: schema.typescriptConfiguration ?? false,
|
|
48
|
+
dynamic: schema.dynamic ?? false,
|
|
47
49
|
};
|
|
48
50
|
const initAppTask = await (0, application_1.default)(host, {
|
|
49
51
|
...options,
|
|
@@ -75,6 +77,14 @@ async function remoteGeneratorInternal(host, schema) {
|
|
|
75
77
|
projectConfig.targets.server.options.webpackConfig = (0, devkit_1.joinPathFragments)(projectConfig.root, `webpack.server.config.${options.typescriptConfiguration ? 'ts' : 'js'}`);
|
|
76
78
|
(0, devkit_1.updateProjectConfiguration)(host, options.projectName, projectConfig);
|
|
77
79
|
}
|
|
80
|
+
if (!options.setParserOptionsProject) {
|
|
81
|
+
host.delete((0, devkit_1.joinPathFragments)(options.appProjectRoot, 'tsconfig.lint.json'));
|
|
82
|
+
}
|
|
83
|
+
if (options.host && options.dynamic) {
|
|
84
|
+
const hostConfig = (0, devkit_1.readProjectConfiguration)(host, schema.host);
|
|
85
|
+
const pathToMFManifest = (0, devkit_1.joinPathFragments)(hostConfig.sourceRoot, 'assets/module-federation.manifest.json');
|
|
86
|
+
(0, add_remote_to_dynamic_host_1.addRemoteToDynamicHost)(host, options.name, options.devServerPort, pathToMFManifest);
|
|
87
|
+
}
|
|
78
88
|
if (!options.skipFormat) {
|
|
79
89
|
await (0, devkit_1.formatFiles)(host);
|
|
80
90
|
}
|
|
@@ -28,6 +28,12 @@
|
|
|
28
28
|
"type": "string",
|
|
29
29
|
"enum": ["as-provided", "derived"]
|
|
30
30
|
},
|
|
31
|
+
"dynamic": {
|
|
32
|
+
"type": "boolean",
|
|
33
|
+
"description": "Should the host application use dynamic federation?",
|
|
34
|
+
"default": false,
|
|
35
|
+
"x-priority": "internal"
|
|
36
|
+
},
|
|
31
37
|
"style": {
|
|
32
38
|
"description": "The file extension to be used for style files.",
|
|
33
39
|
"type": "string",
|
|
@@ -8,6 +8,13 @@ function getFunctionDeterminateRemoteUrl(isServer = false) {
|
|
|
8
8
|
const target = isServer ? 'serve-server' : 'serve';
|
|
9
9
|
const remoteEntry = isServer ? 'server/remoteEntry.js' : 'remoteEntry.js';
|
|
10
10
|
return function (remote) {
|
|
11
|
+
const mappedStaticRemotesFromEnv = process.env
|
|
12
|
+
.NX_MF_DEV_SERVER_STATIC_REMOTES
|
|
13
|
+
? JSON.parse(process.env.NX_MF_DEV_SERVER_STATIC_REMOTES)
|
|
14
|
+
: undefined;
|
|
15
|
+
if (mappedStaticRemotesFromEnv && mappedStaticRemotesFromEnv[remote]) {
|
|
16
|
+
return `${mappedStaticRemotesFromEnv[remote]}/${remoteEntry}`;
|
|
17
|
+
}
|
|
11
18
|
let remoteConfiguration = null;
|
|
12
19
|
try {
|
|
13
20
|
remoteConfiguration = (0, project_graph_1.readCachedProjectConfiguration)(remote);
|
|
@@ -14,6 +14,14 @@ function updateModuleFederationProject(host, options) {
|
|
|
14
14
|
...projectConfig.targets.build.configurations.production,
|
|
15
15
|
webpackConfig: `${options.appProjectRoot}/webpack.config.prod.${options.typescriptConfiguration ? 'ts' : 'js'}`,
|
|
16
16
|
};
|
|
17
|
+
// If host should be configured to use dynamic federation
|
|
18
|
+
if (options.dynamic) {
|
|
19
|
+
const pathToProdWebpackConfig = (0, devkit_1.joinPathFragments)(projectConfig.root, `webpack.prod.config.${options.typescriptConfiguration ? 'ts' : 'js'}`);
|
|
20
|
+
if (host.exists(pathToProdWebpackConfig)) {
|
|
21
|
+
host.delete(pathToProdWebpackConfig);
|
|
22
|
+
}
|
|
23
|
+
delete projectConfig.targets.build.configurations.production?.webpackConfig;
|
|
24
|
+
}
|
|
17
25
|
projectConfig.targets.serve.executor =
|
|
18
26
|
'@nx/react:module-federation-dev-server';
|
|
19
27
|
projectConfig.targets.serve.options.port = options.devServerPort;
|