@nx/react 19.6.0-canary.20240814-6d83ae2 → 19.6.0-rc.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/migrations.json +12 -0
- package/package.json +8 -7
- package/src/executors/module-federation-dev-server/module-federation-dev-server.impl.js +8 -11
- package/src/executors/module-federation-ssr-dev-server/module-federation-ssr-dev-server.impl.d.ts +13 -3
- package/src/executors/module-federation-ssr-dev-server/module-federation-ssr-dev-server.impl.js +180 -80
- package/src/executors/module-federation-ssr-dev-server/schema.json +27 -0
- package/src/generators/component-cypress-spec/schema.json +2 -1
- package/src/generators/host/files/module-federation/webpack.config.js__tmpl__ +6 -1
- package/src/generators/host/files/module-federation/webpack.config.prod.js__tmpl__ +6 -1
- package/src/generators/host/files/module-federation-ssr/server.ts__tmpl__ +1 -1
- package/src/generators/host/files/module-federation-ssr/webpack.server.config.js__tmpl__ +6 -1
- package/src/generators/host/files/module-federation-ssr-ts/server.ts__tmpl__ +1 -1
- package/src/generators/host/files/module-federation-ssr-ts/webpack.server.config.ts__tmpl__ +6 -1
- package/src/generators/host/files/module-federation-ts/webpack.config.prod.ts__tmpl__ +6 -1
- package/src/generators/host/files/module-federation-ts/webpack.config.ts__tmpl__ +6 -1
- package/src/generators/host/lib/setup-ssr-for-host.js +1 -0
- package/src/generators/remote/files/module-federation/webpack.config.js__tmpl__ +6 -1
- package/src/generators/remote/files/module-federation-ssr/server.ts__tmpl__ +1 -1
- package/src/generators/remote/files/module-federation-ssr/webpack.server.config.js__tmpl__ +6 -1
- package/src/generators/remote/files/module-federation-ssr-ts/server.ts__tmpl__ +1 -1
- package/src/generators/remote/files/module-federation-ssr-ts/webpack.server.config.ts__tmpl__ +6 -1
- package/src/generators/remote/files/module-federation-ts/webpack.config.ts__tmpl__ +6 -1
- package/src/generators/remote/lib/setup-ssr-for-remote.js +1 -0
- package/src/generators/setup-ssr/files/server.ts__tmpl__ +2 -2
- package/src/generators/setup-ssr/setup-ssr.js +1 -0
- package/src/generators/stories/schema.json +4 -2
- package/src/migrations/update-19-6-0/turn-off-dts-by-default.d.ts +2 -0
- package/src/migrations/update-19-6-0/turn-off-dts-by-default.js +56 -0
- package/src/migrations/update-19-6-0/update-ssr-server-port.d.ts +2 -0
- package/src/migrations/update-19-6-0/update-ssr-server-port.js +74 -0
package/migrations.json
CHANGED
@@ -41,6 +41,18 @@
|
|
41
41
|
"version": "18.1.1-beta.0",
|
42
42
|
"description": "Ensure targetDefaults inputs for task hashing when '@nx/webpack:webpack' is used are correct for Module Federation.",
|
43
43
|
"factory": "./src/migrations/update-18-1-1/fix-target-defaults-inputs"
|
44
|
+
},
|
45
|
+
"update-19-6-0-turn-module-federation-dts-off": {
|
46
|
+
"cli": "nx",
|
47
|
+
"version": "19.6.0-beta.4",
|
48
|
+
"description": "Ensure Module Federation DTS is turned off by default.",
|
49
|
+
"factory": "./src/migrations/update-19-6-0/turn-off-dts-by-default"
|
50
|
+
},
|
51
|
+
"update-module-federation-ssr-server-file": {
|
52
|
+
"cli": "nx",
|
53
|
+
"version": "19.6.0-beta.4",
|
54
|
+
"description": "Update the server file for Module Federation SSR port value to be the same as the 'serve' target port value.",
|
55
|
+
"factory": "./src/migrations/update-19-6-0/update-ssr-server-port"
|
44
56
|
}
|
45
57
|
},
|
46
58
|
"packageJsonUpdates": {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@nx/react",
|
3
|
-
"version": "19.6.0-
|
3
|
+
"version": "19.6.0-rc.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,14 +39,15 @@
|
|
39
39
|
"minimatch": "9.0.3",
|
40
40
|
"tslib": "^2.3.0",
|
41
41
|
"@module-federation/enhanced": "~0.2.3",
|
42
|
-
"@nx/devkit": "19.6.0-
|
43
|
-
"@nx/js": "19.6.0-
|
44
|
-
"@nx/eslint": "19.6.0-
|
45
|
-
"@nx/web": "19.6.0-
|
46
|
-
"@nrwl/react": "19.6.0-
|
42
|
+
"@nx/devkit": "19.6.0-rc.0",
|
43
|
+
"@nx/js": "19.6.0-rc.0",
|
44
|
+
"@nx/eslint": "19.6.0-rc.0",
|
45
|
+
"@nx/web": "19.6.0-rc.0",
|
46
|
+
"@nrwl/react": "19.6.0-rc.0"
|
47
47
|
},
|
48
48
|
"publishConfig": {
|
49
49
|
"access": "public"
|
50
50
|
},
|
51
|
-
"type": "commonjs"
|
51
|
+
"type": "commonjs",
|
52
|
+
"types": "./index.d.ts"
|
52
53
|
}
|
@@ -9,8 +9,6 @@ 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
10
|
const cache_directory_1 = require("nx/src/utils/cache-directory");
|
11
11
|
const node_child_process_1 = require("node:child_process");
|
12
|
-
const node_path_1 = require("node:path");
|
13
|
-
const node_fs_1 = require("node:fs");
|
14
12
|
const fs_1 = require("fs");
|
15
13
|
const path_1 = require("path");
|
16
14
|
const start_remote_proxies_1 = require("@nx/webpack/src/utils/module-federation/start-remote-proxies");
|
@@ -40,10 +38,10 @@ function startStaticRemotesFileServer(staticRemotesConfig, context, options) {
|
|
40
38
|
}
|
41
39
|
}
|
42
40
|
if (shouldMoveToCommonLocation) {
|
43
|
-
commonOutputDirectory = (0,
|
41
|
+
commonOutputDirectory = (0, path_1.join)(devkit_1.workspaceRoot, 'tmp/static-remotes');
|
44
42
|
for (const app of staticRemotesConfig.remotes) {
|
45
43
|
const remoteConfig = staticRemotesConfig.config[app];
|
46
|
-
(0,
|
44
|
+
(0, fs_1.cpSync)(remoteConfig.outputPath, (0, path_1.join)(commonOutputDirectory, remoteConfig.urlSegment), {
|
47
45
|
force: true,
|
48
46
|
recursive: true,
|
49
47
|
});
|
@@ -103,7 +101,6 @@ async function buildStaticRemotes(staticRemotesConfig, nxBin, context, options)
|
|
103
101
|
for (const app of staticRemotesConfig.remotes) {
|
104
102
|
mappedLocationOfRemotes[app] = `http${options.ssl ? 's' : ''}://${options.host}:${options.staticRemotesPort}/${staticRemotesConfig.config[app].urlSegment}`;
|
105
103
|
}
|
106
|
-
process.env.NX_MF_DEV_SERVER_STATIC_REMOTES = JSON.stringify(mappedLocationOfRemotes);
|
107
104
|
await new Promise((res, rej) => {
|
108
105
|
const staticProcess = (0, node_child_process_1.fork)(nxBin, [
|
109
106
|
'run-many',
|
@@ -118,8 +115,8 @@ async function buildStaticRemotes(staticRemotesConfig, nxBin, context, options)
|
|
118
115
|
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
119
116
|
});
|
120
117
|
// File to debug build failures e.g. 2024-01-01T00_00_0_0Z-build.log'
|
121
|
-
const remoteBuildLogFile = (0,
|
122
|
-
const stdoutStream = (0,
|
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);
|
123
120
|
staticProcess.stdout.on('data', (data) => {
|
124
121
|
const ANSII_CODE_REGEX = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
125
122
|
const stdoutString = data.toString().replace(ANSII_CODE_REGEX, '');
|
@@ -167,9 +164,9 @@ async function* moduleFederationDevServer(options, context) {
|
|
167
164
|
: (0, dev_server_impl_1.default)(options, context);
|
168
165
|
const p = context.projectsConfigurations.projects[context.projectName];
|
169
166
|
const buildOptions = getBuildOptions(options.buildTarget, context);
|
170
|
-
let pathToManifestFile = (0,
|
167
|
+
let pathToManifestFile = (0, path_1.join)(context.root, p.sourceRoot, 'assets/module-federation.manifest.json');
|
171
168
|
if (options.pathToManifestFile) {
|
172
|
-
const userPathToManifestFile = (0,
|
169
|
+
const userPathToManifestFile = (0, path_1.join)(context.root, options.pathToManifestFile);
|
173
170
|
if (!(0, fs_1.existsSync)(userPathToManifestFile)) {
|
174
171
|
throw new Error(`The provided Module Federation manifest file path does not exist. Please check the file exists at "${userPathToManifestFile}".`);
|
175
172
|
}
|
@@ -197,8 +194,8 @@ async function* moduleFederationDevServer(options, context) {
|
|
197
194
|
const staticRemotesIter = startStaticRemotesFileServer(staticRemotesConfig, context, options);
|
198
195
|
(0, start_remote_proxies_1.startRemoteProxies)(staticRemotesConfig, mappedLocationsOfStaticRemotes, options.ssl
|
199
196
|
? {
|
200
|
-
pathToCert: (0,
|
201
|
-
pathToKey: (0,
|
197
|
+
pathToCert: (0, path_1.join)(devkit_1.workspaceRoot, options.sslCert),
|
198
|
+
pathToKey: (0, path_1.join)(devkit_1.workspaceRoot, options.sslKey),
|
202
199
|
}
|
203
200
|
: undefined);
|
204
201
|
return yield* (0, async_iterable_1.combineAsyncIterables)(currIter, ...devRemoteIters, ...(staticRemotesIter ? [staticRemotesIter] : []), (0, async_iterable_1.createAsyncIterable)(async ({ next, done }) => {
|
package/src/executors/module-federation-ssr-dev-server/module-federation-ssr-dev-server.impl.d.ts
CHANGED
@@ -1,9 +1,19 @@
|
|
1
1
|
import { ExecutorContext } from '@nx/devkit';
|
2
2
|
import { WebSsrDevServerOptions } from '@nx/webpack/src/executors/ssr-dev-server/schema';
|
3
|
-
type
|
4
|
-
devRemotes?: string |
|
3
|
+
type ModuleFederationSsrDevServerOptions = WebSsrDevServerOptions & {
|
4
|
+
devRemotes?: (string | {
|
5
|
+
remoteName: string;
|
6
|
+
configuration: string;
|
7
|
+
})[];
|
5
8
|
skipRemotes?: string[];
|
6
9
|
host: string;
|
10
|
+
pathToManifestFile?: string;
|
11
|
+
staticRemotesPort?: number;
|
12
|
+
parallel?: number;
|
13
|
+
ssl?: boolean;
|
14
|
+
sslKey?: string;
|
15
|
+
sslCert?: string;
|
16
|
+
isInitialHost?: boolean;
|
7
17
|
};
|
8
|
-
export default function moduleFederationSsrDevServer(
|
18
|
+
export default function moduleFederationSsrDevServer(ssrDevServerOptions: ModuleFederationSsrDevServerOptions, context: ExecutorContext): AsyncGenerator<any, any, any>;
|
9
19
|
export {};
|
package/src/executors/module-federation-ssr-dev-server/module-federation-ssr-dev-server.impl.js
CHANGED
@@ -4,11 +4,23 @@ exports.default = moduleFederationSsrDevServer;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
5
5
|
const ssr_dev_server_impl_1 = require("@nx/webpack/src/executors/ssr-dev-server/ssr-dev-server.impl");
|
6
6
|
const path_1 = require("path");
|
7
|
-
const
|
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 child_process_1 = require("child_process");
|
10
10
|
const fs_1 = require("fs");
|
11
|
-
const
|
11
|
+
const parse_static_remotes_config_1 = require("@nx/webpack/src/utils/module-federation/parse-static-remotes-config");
|
12
|
+
const file_server_impl_1 = require("@nx/web/src/executors/file-server/file-server.impl");
|
13
|
+
const cache_directory_1 = require("nx/src/utils/cache-directory");
|
14
|
+
const start_ssr_remote_proxies_1 = require("@nx/webpack/src/utils/module-federation/start-ssr-remote-proxies");
|
15
|
+
const wait_for_port_open_1 = require("@nx/web/src/utils/wait-for-port-open");
|
16
|
+
function normalizeOptions(options) {
|
17
|
+
return {
|
18
|
+
...options,
|
19
|
+
ssl: options.ssl ?? false,
|
20
|
+
sslCert: options.sslCert ? (0, path_1.join)(devkit_1.workspaceRoot, options.sslCert) : undefined,
|
21
|
+
sslKey: options.sslKey ? (0, path_1.join)(devkit_1.workspaceRoot, options.sslKey) : undefined,
|
22
|
+
};
|
23
|
+
}
|
12
24
|
function getBuildOptions(buildTarget, context) {
|
13
25
|
const target = (0, devkit_1.parseTargetString)(buildTarget, context);
|
14
26
|
const buildOptions = (0, devkit_1.readTargetOptions)(target, context);
|
@@ -16,93 +28,181 @@ function getBuildOptions(buildTarget, context) {
|
|
16
28
|
...buildOptions,
|
17
29
|
};
|
18
30
|
}
|
19
|
-
function
|
20
|
-
|
21
|
-
|
22
|
-
let moduleFederationConfigPath = moduleFederationConfigPathJS;
|
23
|
-
const fullTSconfigPath = tsconfigPath.startsWith(workspaceRoot)
|
24
|
-
? tsconfigPath
|
25
|
-
: (0, path_1.join)(workspaceRoot, tsconfigPath);
|
26
|
-
// create a no-op so this can be called with issue
|
27
|
-
let cleanupTranspiler = () => { };
|
28
|
-
if ((0, fs_1.existsSync)(moduleFederationConfigPathTS)) {
|
29
|
-
cleanupTranspiler = (0, internal_1.registerTsProject)(fullTSconfigPath);
|
30
|
-
moduleFederationConfigPath = moduleFederationConfigPathTS;
|
31
|
+
function startSsrStaticRemotesFileServer(ssrStaticRemotesConfig, context, options) {
|
32
|
+
if (ssrStaticRemotesConfig.remotes.length === 0) {
|
33
|
+
return;
|
31
34
|
}
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
35
|
+
// The directories are usually generated with /browser and /server suffixes so we need to copy them to a common directory
|
36
|
+
const commonOutputDirectory = (0, path_1.join)(devkit_1.workspaceRoot, 'tmp/static-remotes');
|
37
|
+
for (const app of ssrStaticRemotesConfig.remotes) {
|
38
|
+
const remoteConfig = ssrStaticRemotesConfig.config[app];
|
39
|
+
(0, fs_1.cpSync)(remoteConfig.outputPath, (0, path_1.join)(commonOutputDirectory, remoteConfig.urlSegment), {
|
40
|
+
force: true,
|
41
|
+
recursive: true,
|
42
|
+
});
|
36
43
|
}
|
37
|
-
|
38
|
-
|
44
|
+
const staticRemotesIter = (0, file_server_impl_1.default)({
|
45
|
+
cors: true,
|
46
|
+
watch: false,
|
47
|
+
staticFilePath: commonOutputDirectory,
|
48
|
+
parallel: false,
|
49
|
+
spa: false,
|
50
|
+
withDeps: false,
|
51
|
+
host: options.host,
|
52
|
+
port: options.staticRemotesPort,
|
53
|
+
ssl: options.ssl,
|
54
|
+
sslCert: options.sslCert,
|
55
|
+
sslKey: options.sslKey,
|
56
|
+
cacheSeconds: -1,
|
57
|
+
}, context);
|
58
|
+
return staticRemotesIter;
|
59
|
+
}
|
60
|
+
async function startRemotes(remotes, context, options) {
|
61
|
+
const remoteIters = [];
|
62
|
+
const target = 'serve';
|
63
|
+
for (const app of remotes) {
|
64
|
+
const remoteProjectServeTarget = context.projectGraph.nodes[app].data.targets[target];
|
65
|
+
const isUsingModuleFederationSsrDevServerExecutor = remoteProjectServeTarget.executor.includes('module-federation-ssr-dev-server');
|
66
|
+
const configurationOverride = options.devRemotes?.find((remote) => typeof remote !== 'string' && remote.remoteName === app)?.configuration;
|
67
|
+
{
|
68
|
+
const defaultOverrides = {
|
69
|
+
...(options.host ? { host: options.host } : {}),
|
70
|
+
...(options.ssl ? { ssl: options.ssl } : {}),
|
71
|
+
...(options.sslCert ? { sslCert: options.sslCert } : {}),
|
72
|
+
...(options.sslKey ? { sslKey: options.sslKey } : {}),
|
73
|
+
};
|
74
|
+
const overrides = {
|
75
|
+
watch: true,
|
76
|
+
...defaultOverrides,
|
77
|
+
...(isUsingModuleFederationSsrDevServerExecutor
|
78
|
+
? { isInitialHost: false }
|
79
|
+
: {}),
|
80
|
+
};
|
81
|
+
remoteIters.push(await (0, devkit_1.runExecutor)({
|
82
|
+
project: app,
|
83
|
+
target,
|
84
|
+
configuration: configurationOverride ?? context.configurationName,
|
85
|
+
}, overrides, context));
|
86
|
+
}
|
39
87
|
}
|
88
|
+
return remoteIters;
|
89
|
+
}
|
90
|
+
async function buildSsrStaticRemotes(staticRemotesConfig, nxBin, context, options) {
|
91
|
+
if (!staticRemotesConfig.remotes.length) {
|
92
|
+
return;
|
93
|
+
}
|
94
|
+
devkit_1.logger.info(`Nx is building ${staticRemotesConfig.remotes.length} static remotes...`);
|
95
|
+
const mapLocationOfRemotes = {};
|
96
|
+
for (const remoteApp of staticRemotesConfig.remotes) {
|
97
|
+
mapLocationOfRemotes[remoteApp] = `http${options.ssl ? 's' : ''}://${options.host}:${options.staticRemotesPort}/${staticRemotesConfig.config[remoteApp].urlSegment}`;
|
98
|
+
}
|
99
|
+
await new Promise((resolve) => {
|
100
|
+
const childProcess = (0, child_process_1.fork)(nxBin, [
|
101
|
+
'run-many',
|
102
|
+
'--target=server',
|
103
|
+
'--projects',
|
104
|
+
staticRemotesConfig.remotes.join(','),
|
105
|
+
...(context.configurationName
|
106
|
+
? [`--configuration=${context.configurationName}`]
|
107
|
+
: []),
|
108
|
+
...(options.parallel ? [`--parallel=${options.parallel}`] : []),
|
109
|
+
], {
|
110
|
+
cwd: context.root,
|
111
|
+
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
112
|
+
});
|
113
|
+
// Add a listener to the child process to capture the build log
|
114
|
+
const remoteBuildLogFile = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, `${new Date().toISOString().replace(/[:\.]/g, '_')}-build.log`);
|
115
|
+
const remoteBuildLogStream = (0, fs_1.createWriteStream)(remoteBuildLogFile);
|
116
|
+
childProcess.stdout.on('data', (data) => {
|
117
|
+
const ANSII_CODE_REGEX = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
118
|
+
const stdoutString = data.toString().replace(ANSII_CODE_REGEX, '');
|
119
|
+
remoteBuildLogStream.write(stdoutString);
|
120
|
+
// in addition to writing into the stdout stream, also show error directly in console
|
121
|
+
// so the error is easily discoverable. 'ERROR in' is the key word to search in webpack output.
|
122
|
+
if (stdoutString.includes('ERROR in')) {
|
123
|
+
devkit_1.logger.log(stdoutString);
|
124
|
+
}
|
125
|
+
if (stdoutString.includes('Successfully ran target server')) {
|
126
|
+
childProcess.stdout.removeAllListeners('data');
|
127
|
+
devkit_1.logger.info(`Nx Built ${staticRemotesConfig.remotes.length} static remotes.`);
|
128
|
+
resolve();
|
129
|
+
}
|
130
|
+
});
|
131
|
+
process.on('SIGTERM', () => childProcess.kill('SIGTERM'));
|
132
|
+
process.on('exit', () => childProcess.kill('SIGTERM'));
|
133
|
+
});
|
134
|
+
return mapLocationOfRemotes;
|
40
135
|
}
|
41
|
-
async function* moduleFederationSsrDevServer(
|
136
|
+
async function* moduleFederationSsrDevServer(ssrDevServerOptions, context) {
|
137
|
+
const options = normalizeOptions(ssrDevServerOptions);
|
138
|
+
// Force Node to resolve to look for the nx binary that is inside node_modules
|
139
|
+
const nxBin = require.resolve('nx/bin/nx');
|
42
140
|
let iter = (0, ssr_dev_server_impl_1.default)(options, context);
|
43
|
-
const
|
141
|
+
const projectConfig = context.projectsConfigurations.projects[context.projectName];
|
44
142
|
const buildOptions = getBuildOptions(options.browserTarget, context);
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
if (remotesToSkip.has(validRemote)) {
|
51
|
-
return false;
|
143
|
+
let pathToManifestFile = (0, path_1.join)(context.root, projectConfig.sourceRoot, 'assets/module-federation.manifest.json');
|
144
|
+
if (options.pathToManifestFile) {
|
145
|
+
const userPathToManifestFile = (0, path_1.join)(context.root, options.pathToManifestFile);
|
146
|
+
if (!(0, fs_1.existsSync)(userPathToManifestFile)) {
|
147
|
+
throw new Error(`The provided Module Federation manifest file path does not exist. Please check the file exists at "${userPathToManifestFile}".`);
|
52
148
|
}
|
53
|
-
else if (
|
54
|
-
|
55
|
-
return false;
|
149
|
+
else if ((0, path_1.extname)(userPathToManifestFile) !== '.json') {
|
150
|
+
throw new Error(`The Module Federation manifest file must be a JSON. Please ensure the file at ${userPathToManifestFile} is a JSON.`);
|
56
151
|
}
|
57
|
-
|
58
|
-
return true;
|
59
|
-
}
|
60
|
-
});
|
61
|
-
if (remotesNotInWorkspace.length > 0) {
|
62
|
-
devkit_1.logger.warn(`Skipping serving ${remotesNotInWorkspace.join(', ')} as they could not be found in the workspace. Ensure they are served correctly.`);
|
152
|
+
pathToManifestFile = userPathToManifestFile;
|
63
153
|
}
|
64
|
-
|
65
|
-
|
66
|
-
: Array.isArray(options.devRemotes)
|
67
|
-
? options.devRemotes
|
68
|
-
: [options.devRemotes];
|
69
|
-
// Set NX_MF_DEV_REMOTES for the Nx Runtime Library Control Plugin
|
70
|
-
process.env.NX_MF_DEV_REMOTES = JSON.stringify(devServeApps);
|
71
|
-
for (const app of knownRemotes) {
|
72
|
-
const [appName] = Array.isArray(app) ? app : [app];
|
73
|
-
const isDev = devServeApps.includes(appName);
|
74
|
-
const remoteServeIter = isDev
|
75
|
-
? await (0, devkit_1.runExecutor)({
|
76
|
-
project: appName,
|
77
|
-
target: 'serve',
|
78
|
-
configuration: context.configurationName,
|
79
|
-
}, {
|
80
|
-
watch: isDev,
|
81
|
-
}, context)
|
82
|
-
: (0, async_iterable_1.mapAsyncIterable)((0, async_iterable_1.createAsyncIterable)(async ({ next, done }) => {
|
83
|
-
const remoteProject = context.projectsConfigurations.projects[appName];
|
84
|
-
const remoteServerOutput = (0, path_1.join)(devkit_1.workspaceRoot, remoteProject.targets.server.options.outputPath, remoteProject.targets.server.options.outputFileName);
|
85
|
-
const pm = (0, devkit_1.getPackageManagerCommand)();
|
86
|
-
(0, child_process_1.execSync)(`${pm.exec} nx run ${appName}:server${context.configurationName ? `:${context.configurationName}` : ''}`, { stdio: 'inherit' });
|
87
|
-
const child = (0, child_process_1.fork)(remoteServerOutput, {
|
88
|
-
env: {
|
89
|
-
PORT: remoteProject.targets['serve-browser'].options.port,
|
90
|
-
},
|
91
|
-
});
|
92
|
-
child.on('message', (msg) => {
|
93
|
-
if (msg === 'nx.server.ready') {
|
94
|
-
next(true);
|
95
|
-
done();
|
96
|
-
}
|
97
|
-
});
|
98
|
-
}), (x) => x);
|
99
|
-
iter = (0, async_iterable_1.combineAsyncIterables)(iter, remoteServeIter);
|
154
|
+
if (!options.isInitialHost) {
|
155
|
+
return yield* iter;
|
100
156
|
}
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
157
|
+
const moduleFederationConfig = (0, module_federation_1.getModuleFederationConfig)(buildOptions.tsConfig, context.root, projectConfig.root, 'react');
|
158
|
+
const remoteNames = options.devRemotes?.map((remote) => typeof remote === 'string' ? remote : remote.remoteName);
|
159
|
+
const remotes = (0, module_federation_1.getRemotes)(remoteNames, options.skipRemotes, moduleFederationConfig, {
|
160
|
+
projectName: context.projectName,
|
161
|
+
projectGraph: context.projectGraph,
|
162
|
+
root: context.root,
|
163
|
+
}, pathToManifestFile);
|
164
|
+
options.staticRemotesPort ??= remotes.staticRemotePort;
|
165
|
+
process.env.NX_MF_DEV_REMOTES = JSON.stringify(remotes.devRemotes.map((r) => (typeof r === 'string' ? r : r.remoteName)));
|
166
|
+
const staticRemotesConfig = (0, parse_static_remotes_config_1.parseStaticSsrRemotesConfig)([...remotes.staticRemotes, ...remotes.dynamicRemotes], context);
|
167
|
+
const mappedLocationsOfStaticRemotes = await buildSsrStaticRemotes(staticRemotesConfig, nxBin, context, options);
|
168
|
+
const devRemoteIters = await startRemotes(remotes.devRemotes, context, options);
|
169
|
+
const staticRemotesIter = startSsrStaticRemotesFileServer(staticRemotesConfig, context, options);
|
170
|
+
(0, start_ssr_remote_proxies_1.startSsrRemoteProxies)(staticRemotesConfig, mappedLocationsOfStaticRemotes, options.ssl
|
171
|
+
? {
|
172
|
+
pathToCert: options.sslCert,
|
173
|
+
pathToKey: options.sslKey,
|
106
174
|
}
|
107
|
-
|
175
|
+
: undefined);
|
176
|
+
return yield* (0, async_iterable_1.combineAsyncIterables)(iter, ...devRemoteIters, ...(staticRemotesIter ? [staticRemotesIter] : []), (0, async_iterable_1.createAsyncIterable)(async ({ next, done }) => {
|
177
|
+
if (!options.isInitialHost) {
|
178
|
+
done();
|
179
|
+
return;
|
180
|
+
}
|
181
|
+
if (remotes.remotePorts.length === 0) {
|
182
|
+
done();
|
183
|
+
return;
|
184
|
+
}
|
185
|
+
try {
|
186
|
+
const host = options.host ?? 'localhost';
|
187
|
+
const baseUrl = `http${options.ssl ? 's' : ''}://${host}:${options.port}`;
|
188
|
+
const portsToWaitFor = staticRemotesIter
|
189
|
+
? [options.staticRemotesPort, ...remotes.remotePorts]
|
190
|
+
: [...remotes.remotePorts];
|
191
|
+
await Promise.all(portsToWaitFor.map((port) => (0, wait_for_port_open_1.waitForPortOpen)(port, {
|
192
|
+
retries: 480,
|
193
|
+
retryDelay: 2500,
|
194
|
+
host,
|
195
|
+
})));
|
196
|
+
devkit_1.logger.info(`Nx all ssr remotes have started, server ready at ${baseUrl}`);
|
197
|
+
next({ success: true, baseUrl });
|
198
|
+
}
|
199
|
+
catch (error) {
|
200
|
+
throw new Error(`Nx failed to start ssr remotes. Check above for errors.`, {
|
201
|
+
cause: error,
|
202
|
+
});
|
203
|
+
}
|
204
|
+
finally {
|
205
|
+
done();
|
206
|
+
}
|
207
|
+
}));
|
108
208
|
}
|
@@ -42,6 +42,33 @@
|
|
42
42
|
"type": "string",
|
43
43
|
"description": "Host to listen on.",
|
44
44
|
"default": "localhost"
|
45
|
+
},
|
46
|
+
"staticRemotesPort": {
|
47
|
+
"type": "number",
|
48
|
+
"description": "The port at which to serve the file-server for the static remotes."
|
49
|
+
},
|
50
|
+
"pathToManifestFile": {
|
51
|
+
"type": "string",
|
52
|
+
"description": "Path to a Module Federation manifest file (e.g. `my/path/to/module-federation.manifest.json`) containing the dynamic remote applications relative to the workspace root."
|
53
|
+
},
|
54
|
+
"ssl": {
|
55
|
+
"type": "boolean",
|
56
|
+
"description": "Serve using HTTPS.",
|
57
|
+
"default": false
|
58
|
+
},
|
59
|
+
"sslKey": {
|
60
|
+
"type": "string",
|
61
|
+
"description": "SSL key to use for serving HTTPS."
|
62
|
+
},
|
63
|
+
"sslCert": {
|
64
|
+
"type": "string",
|
65
|
+
"description": "SSL certificate to use for serving HTTPS."
|
66
|
+
},
|
67
|
+
"isInitialHost": {
|
68
|
+
"type": "boolean",
|
69
|
+
"description": "Whether the host that is running this executor is the first in the project tree to do so.",
|
70
|
+
"default": true,
|
71
|
+
"x-priority": "internal"
|
45
72
|
}
|
46
73
|
},
|
47
74
|
"required": ["browserTarget", "serverTarget"]
|
@@ -3,7 +3,8 @@
|
|
3
3
|
"cli": "nx",
|
4
4
|
"$id": "NxReactComponentCypressSpec",
|
5
5
|
"title": "Create component Cypress spec",
|
6
|
-
"description": "Create a Cypress spec for a UI component that has a story.",
|
6
|
+
"description": "Create a Storybook Cypress spec for a UI component that has a story.",
|
7
|
+
"x-deprecated": "Use interactionTests instead. This option will be removed in v20.",
|
7
8
|
"type": "object",
|
8
9
|
"properties": {
|
9
10
|
"project": {
|
@@ -9,4 +9,9 @@ const config = {
|
|
9
9
|
};
|
10
10
|
|
11
11
|
// Nx plugins for webpack to build config object from Nx options and context.
|
12
|
-
|
12
|
+
/**
|
13
|
+
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support for Module Federation
|
14
|
+
* The DTS Plugin can be enabled by setting dts: true
|
15
|
+
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
16
|
+
*/
|
17
|
+
module.exports = composePlugins(withNx(), withReact(), withModuleFederation(config, { dts: false }));
|
@@ -29,4 +29,9 @@ const prodConfig = {
|
|
29
29
|
};
|
30
30
|
|
31
31
|
// Nx plugins for webpack to build config object from Nx options and context.
|
32
|
-
|
32
|
+
/**
|
33
|
+
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support for Module Federation
|
34
|
+
* The DTS Plugin can be enabled by setting dts: true
|
35
|
+
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
36
|
+
*/
|
37
|
+
module.exports = composePlugins(withNx(), withReact(), withModuleFederation(prodConfig, { dts: false }));
|
@@ -4,7 +4,7 @@ import cors from 'cors';
|
|
4
4
|
|
5
5
|
import { handleRequest } from './src/main.server';
|
6
6
|
|
7
|
-
const port = process.env['PORT'] ||
|
7
|
+
const port = process.env['PORT'] || <%= port %>;
|
8
8
|
const app = express();
|
9
9
|
|
10
10
|
const browserDist = path.join(process.cwd(), '<%= browserBuildOutputPath %>');
|
@@ -9,4 +9,9 @@ const defaultConfig = {
|
|
9
9
|
};
|
10
10
|
|
11
11
|
// Nx plugins for webpack to build config object from Nx options and context.
|
12
|
-
|
12
|
+
/**
|
13
|
+
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support for Module Federation
|
14
|
+
* The DTS Plugin can be enabled by setting dts: true
|
15
|
+
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
16
|
+
*/
|
17
|
+
module.exports = composePlugins(withNx(), withReact({ssr: true}), withModuleFederationForSSR(defaultConfig, { dts: false }));
|
@@ -4,7 +4,7 @@ import cors from 'cors';
|
|
4
4
|
|
5
5
|
import { handleRequest } from './src/main.server';
|
6
6
|
|
7
|
-
const port = process.env['PORT'] ||
|
7
|
+
const port = process.env['PORT'] || <%= port %>;
|
8
8
|
const app = express();
|
9
9
|
|
10
10
|
const browserDist = path.join(process.cwd(), '<%= browserBuildOutputPath %>');
|
@@ -9,4 +9,9 @@ const defaultConfig = {
|
|
9
9
|
};
|
10
10
|
|
11
11
|
// Nx plugins for webpack to build config object from Nx options and context.
|
12
|
-
|
12
|
+
/**
|
13
|
+
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support for Module Federation
|
14
|
+
* The DTS Plugin can be enabled by setting dts: true
|
15
|
+
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
16
|
+
*/
|
17
|
+
export default composePlugins(withNx(), withReact({ssr: true}), withModuleFederationForSSR(defaultConfig, { dts: false }));
|
@@ -30,4 +30,9 @@ const prodConfig: ModuleFederationConfig = {
|
|
30
30
|
};
|
31
31
|
|
32
32
|
// Nx plugins for webpack to build config object from Nx options and context.
|
33
|
-
|
33
|
+
/**
|
34
|
+
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support for Module Federation
|
35
|
+
* The DTS Plugin can be enabled by setting dts: true
|
36
|
+
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
37
|
+
*/
|
38
|
+
export default composePlugins(withNx(), withReact(), withModuleFederation(prodConfig, { dts: false }));
|
@@ -9,4 +9,9 @@ const config: ModuleFederationConfig = {
|
|
9
9
|
};
|
10
10
|
|
11
11
|
// Nx plugins for webpack to build config object from Nx options and context.
|
12
|
-
|
12
|
+
/**
|
13
|
+
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support for Module Federation
|
14
|
+
* The DTS Plugin can be enabled by setting dts: true
|
15
|
+
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
16
|
+
*/
|
17
|
+
export default composePlugins(withNx(), withReact(), withModuleFederation(config, { dts: false }));
|
@@ -14,6 +14,7 @@ async function setupSsrForHost(tree, options, appName, defaultRemoteManifest) {
|
|
14
14
|
(0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, `../files/${pathToModuleFederationSsrFiles}`), project.root, {
|
15
15
|
...options,
|
16
16
|
static: !options?.dynamic,
|
17
|
+
port: Number(options?.devServerPort) || 4200,
|
17
18
|
remotes: defaultRemoteManifest.map(({ name, port }) => {
|
18
19
|
return {
|
19
20
|
...(0, devkit_1.names)(name),
|
@@ -9,4 +9,9 @@ const config = {
|
|
9
9
|
};
|
10
10
|
|
11
11
|
// Nx plugins for webpack to build config object from Nx options and context.
|
12
|
-
|
12
|
+
/**
|
13
|
+
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support Module Federation
|
14
|
+
* The DTS Plugin can be enabled by setting dts: true
|
15
|
+
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
16
|
+
*/
|
17
|
+
module.exports = composePlugins(withNx(), withReact(), withModuleFederation(config, { dts: false }));
|
@@ -4,7 +4,7 @@ import cors from 'cors';
|
|
4
4
|
|
5
5
|
import { handleRequest } from './src/main.server';
|
6
6
|
|
7
|
-
const port = process.env['PORT'] ||
|
7
|
+
const port = process.env['PORT'] || <%= port %>;
|
8
8
|
const app = express();
|
9
9
|
|
10
10
|
const browserDist = path.join(process.cwd(), '<%= browserBuildOutputPath %>');
|
@@ -9,4 +9,9 @@ const defaultConfig = {
|
|
9
9
|
};
|
10
10
|
|
11
11
|
// Nx plugins for webpack to build config object from Nx options and context.
|
12
|
-
|
12
|
+
/**
|
13
|
+
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support Module Federation
|
14
|
+
* The DTS Plugin can be enabled by setting dts: true
|
15
|
+
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
16
|
+
*/
|
17
|
+
module.exports = composePlugins(withNx(), withReact({ssr: true}), withModuleFederationForSSR(defaultConfig, { dts: false }));
|
@@ -4,7 +4,7 @@ import cors from 'cors';
|
|
4
4
|
|
5
5
|
import { handleRequest } from './src/main.server';
|
6
6
|
|
7
|
-
const port = process.env['PORT'] ||
|
7
|
+
const port = process.env['PORT'] || <%= port %>;
|
8
8
|
const app = express();
|
9
9
|
|
10
10
|
const browserDist = path.join(process.cwd(), '<%= browserBuildOutputPath %>');
|
package/src/generators/remote/files/module-federation-ssr-ts/webpack.server.config.ts__tmpl__
CHANGED
@@ -9,4 +9,9 @@ const defaultConfig = {
|
|
9
9
|
};
|
10
10
|
|
11
11
|
// Nx plugins for webpack to build config object from Nx options and context.
|
12
|
-
|
12
|
+
/**
|
13
|
+
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support Module Federation
|
14
|
+
* The DTS Plugin can be enabled by setting dts: true
|
15
|
+
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
16
|
+
*/
|
17
|
+
export default composePlugins(withNx(), withReact({ssr: true}), withModuleFederationForSSR(defaultConfig, { dts: false }));
|
@@ -9,4 +9,9 @@ const config = {
|
|
9
9
|
};
|
10
10
|
|
11
11
|
// Nx plugins for webpack to build config object from Nx options and context.
|
12
|
-
|
12
|
+
/**
|
13
|
+
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support Module Federation
|
14
|
+
* The DTS Plugin can be enabled by setting dts: true
|
15
|
+
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
16
|
+
*/
|
17
|
+
export default composePlugins(withNx(), withReact(), withModuleFederation(config, { dts: false }));
|
@@ -11,6 +11,7 @@ async function setupSsrForRemote(tree, options, appName) {
|
|
11
11
|
: 'module-federation-ssr';
|
12
12
|
(0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, `../files/${pathToModuleFederationSsrFiles}`), project.root, {
|
13
13
|
...options,
|
14
|
+
port: Number(options?.devServerPort) || 4200,
|
14
15
|
appName,
|
15
16
|
tmpl: '',
|
16
17
|
browserBuildOutputPath: project.targets.build.options.outputPath,
|
@@ -4,11 +4,11 @@ import cors from 'cors';
|
|
4
4
|
|
5
5
|
import { handleRequest } from './src/main.server';
|
6
6
|
|
7
|
-
const port = process.env['PORT'] ||
|
7
|
+
const port = process.env['PORT'] || <%= port %>;
|
8
8
|
const app = express();
|
9
9
|
|
10
10
|
const browserDist = path.join(process.cwd(), '<%= browserBuildOutputPath %>');
|
11
|
-
const indexPath =path.join(browserDist, 'index.html');
|
11
|
+
const indexPath = path.join(browserDist, 'index.html');
|
12
12
|
|
13
13
|
app.use(cors());
|
14
14
|
|
@@ -150,6 +150,7 @@ async function setupSsrGenerator(tree, options) {
|
|
150
150
|
nxJson.targetDefaults.server.cache = true;
|
151
151
|
(0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, 'files'), projectRoot, {
|
152
152
|
tmpl: '',
|
153
|
+
port: Number(options?.serverPort) || 4200,
|
153
154
|
extraInclude: options.extraInclude?.length > 0
|
154
155
|
? `"${options.extraInclude.join('", "')}",`
|
155
156
|
: '',
|
@@ -19,11 +19,13 @@
|
|
19
19
|
},
|
20
20
|
"generateCypressSpecs": {
|
21
21
|
"type": "boolean",
|
22
|
-
"description": "Automatically generate `*.spec.ts` files in the cypress e2e app generated by the cypress-configure generator."
|
22
|
+
"description": "Automatically generate `*.spec.ts` files in the cypress e2e app generated by the cypress-configure generator.",
|
23
|
+
"x-deprecated": "Use interactionTests instead. This option will be removed in v20."
|
23
24
|
},
|
24
25
|
"cypressProject": {
|
25
26
|
"type": "string",
|
26
|
-
"description": "The Cypress project to generate the stories under. This is inferred from `project` by default."
|
27
|
+
"description": "The Cypress project to generate the stories under. This is inferred from `project` by default.",
|
28
|
+
"x-deprecated": "Use interactionTests instead. This option will be removed in v20."
|
27
29
|
},
|
28
30
|
"interactionTests": {
|
29
31
|
"type": "boolean",
|
@@ -0,0 +1,56 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.default = default_1;
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
5
|
+
const minimatch_1 = require("minimatch");
|
6
|
+
const tsquery_1 = require("@phenomnomnominal/tsquery");
|
7
|
+
async function default_1(tree) {
|
8
|
+
(0, devkit_1.visitNotIgnoredFiles)(tree, '', (path) => {
|
9
|
+
const webpackConfigGlob = '**/webpack*.config*.{js,ts,mjs,cjs}';
|
10
|
+
const result = (0, minimatch_1.minimatch)(path, webpackConfigGlob);
|
11
|
+
if (!result) {
|
12
|
+
return;
|
13
|
+
}
|
14
|
+
let webpackConfigContents = tree.read(path, 'utf-8');
|
15
|
+
if (!/withModuleFederationSSR|withModuleFederation/.test(webpackConfigContents)) {
|
16
|
+
return;
|
17
|
+
}
|
18
|
+
const WITH_MODULE_FEDERATION_SELECTOR = 'CallExpression:has(Identifier[name=composePlugins]) > CallExpression:has(Identifier[name=withModuleFederation]),CallExpression:has(Identifier[name=composePlugins]) > CallExpression:has(Identifier[name=withModuleFederationForSSR])';
|
19
|
+
const EXISTING_MF_OVERRIDES_SELECTOR = 'ObjectLiteralExpression';
|
20
|
+
const ast = tsquery_1.tsquery.ast(webpackConfigContents);
|
21
|
+
const withModuleFederationNodes = (0, tsquery_1.tsquery)(ast, WITH_MODULE_FEDERATION_SELECTOR, { visitAllChildren: true });
|
22
|
+
if (!withModuleFederationNodes.length) {
|
23
|
+
return;
|
24
|
+
}
|
25
|
+
const withModuleFederationNode = withModuleFederationNodes[0];
|
26
|
+
const existingOverridesNodes = (0, tsquery_1.tsquery)(withModuleFederationNode, EXISTING_MF_OVERRIDES_SELECTOR, { visitAllChildren: true });
|
27
|
+
if (!existingOverridesNodes.length) {
|
28
|
+
// doesn't exist, add it
|
29
|
+
webpackConfigContents = `${webpackConfigContents.slice(0, withModuleFederationNode.getEnd() - 1)},${JSON.stringify({ dts: false })}${webpackConfigContents.slice(withModuleFederationNode.getEnd() - 1)}`;
|
30
|
+
}
|
31
|
+
else {
|
32
|
+
let existingOverrideNode;
|
33
|
+
for (const node of existingOverridesNodes) {
|
34
|
+
if (!existingOverrideNode) {
|
35
|
+
existingOverrideNode = node;
|
36
|
+
}
|
37
|
+
if (existingOverrideNode.getText().includes(node.getText())) {
|
38
|
+
continue;
|
39
|
+
}
|
40
|
+
existingOverrideNode = node;
|
41
|
+
}
|
42
|
+
const DTS_PROPERTY_SELECTOR = 'PropertyAssignment > Identifier[name=dts]';
|
43
|
+
const dtsPropertyNode = (0, tsquery_1.tsquery)(existingOverrideNode, DTS_PROPERTY_SELECTOR);
|
44
|
+
if (dtsPropertyNode.length) {
|
45
|
+
// dts already exists, do nothing
|
46
|
+
return;
|
47
|
+
}
|
48
|
+
const newOverrides = `{ dts: false, ${existingOverrideNode
|
49
|
+
.getText()
|
50
|
+
.slice(1)}`;
|
51
|
+
webpackConfigContents = `${webpackConfigContents.slice(0, existingOverrideNode.getStart())}${newOverrides}${webpackConfigContents.slice(existingOverrideNode.getEnd())}`;
|
52
|
+
}
|
53
|
+
tree.write(path, webpackConfigContents);
|
54
|
+
});
|
55
|
+
await (0, devkit_1.formatFiles)(tree);
|
56
|
+
}
|
@@ -0,0 +1,74 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.default = update;
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
5
|
+
const tsquery_1 = require("@phenomnomnominal/tsquery");
|
6
|
+
const ts = require("typescript");
|
7
|
+
const minimatch_1 = require("minimatch");
|
8
|
+
const executor_options_utils_1 = require("@nx/devkit/src/generators/executor-options-utils");
|
9
|
+
function update(tree) {
|
10
|
+
const projects = (0, devkit_1.getProjects)(tree);
|
11
|
+
const executors = [
|
12
|
+
'@nx/webpack:ssr-dev-server',
|
13
|
+
'@nx/react:module-federation-ssr-dev-server',
|
14
|
+
];
|
15
|
+
executors.forEach((executor) => {
|
16
|
+
(0, executor_options_utils_1.forEachExecutorOptions)(tree, executor, (options, projectName) => {
|
17
|
+
const project = projects.get(projectName);
|
18
|
+
if (isModuleFederationSSRProject(tree, project)) {
|
19
|
+
const port = options.port;
|
20
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(project.root, 'server.ts'))) {
|
21
|
+
const serverContent = tree.read((0, devkit_1.joinPathFragments)(project.root, 'server.ts'), 'utf-8');
|
22
|
+
if (serverContent && port) {
|
23
|
+
const updatedServerContent = updateServerPort(serverContent, port);
|
24
|
+
if (updatedServerContent) {
|
25
|
+
tree.write((0, devkit_1.joinPathFragments)(project.root, 'server.ts'), updatedServerContent);
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
});
|
31
|
+
});
|
32
|
+
}
|
33
|
+
function updateServerPort(serverContent, port) {
|
34
|
+
const sourceFile = tsquery_1.tsquery.ast(serverContent);
|
35
|
+
const serverPortNode = (0, tsquery_1.tsquery)(sourceFile, `VariableDeclaration:has(Identifier[name="port"])`)[0];
|
36
|
+
if (serverPortNode) {
|
37
|
+
const binaryExpression = (0, tsquery_1.tsquery)(serverPortNode, 'BinaryExpression')[0];
|
38
|
+
if (binaryExpression) {
|
39
|
+
const leftExpression = (0, tsquery_1.tsquery)(binaryExpression, 'PropertyAccessExpression:has(Identifier[name="env"])')[0];
|
40
|
+
const rightExpression = (0, tsquery_1.tsquery)(binaryExpression, 'NumericLiteral[text="4200"]')[0];
|
41
|
+
if (leftExpression && rightExpression) {
|
42
|
+
const serverPortDeclaration = serverPortNode;
|
43
|
+
const newInitializer = ts.factory.createBinaryExpression(
|
44
|
+
// process.env.PORT
|
45
|
+
ts.factory.createPropertyAccessExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('process'), ts.factory.createIdentifier('env')), 'PORT'),
|
46
|
+
// ||
|
47
|
+
ts.SyntaxKind.BarBarToken,
|
48
|
+
// port value
|
49
|
+
ts.factory.createNumericLiteral(port.toString()));
|
50
|
+
const updatePortDeclaration = ts.factory.updateVariableDeclaration(serverPortDeclaration, serverPortDeclaration.name, serverPortDeclaration.exclamationToken, serverPortDeclaration.type, newInitializer);
|
51
|
+
const updatedStatements = sourceFile.statements.map((statement) => {
|
52
|
+
if (ts.isVariableStatement(statement)) {
|
53
|
+
const updatedDeclarationList = statement.declarationList.declarations.map((decl) => decl === serverPortDeclaration ? updatePortDeclaration : decl);
|
54
|
+
const updatedDeclList = ts.factory.updateVariableDeclarationList(statement.declarationList, updatedDeclarationList);
|
55
|
+
return ts.factory.updateVariableStatement(statement, statement.modifiers, updatedDeclList);
|
56
|
+
}
|
57
|
+
return statement;
|
58
|
+
});
|
59
|
+
const updatedSourceFile = ts.factory.updateSourceFile(sourceFile, updatedStatements);
|
60
|
+
const printer = ts.createPrinter();
|
61
|
+
return printer.printNode(ts.EmitHint.Unspecified, updatedSourceFile, sourceFile);
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
66
|
+
function isModuleFederationSSRProject(tree, project) {
|
67
|
+
let hasMfeServerConfig = false;
|
68
|
+
(0, devkit_1.visitNotIgnoredFiles)(tree, project.root, (filePath) => {
|
69
|
+
if ((0, minimatch_1.minimatch)(filePath, '**/module-federation*.server.config.*')) {
|
70
|
+
hasMfeServerConfig = true;
|
71
|
+
}
|
72
|
+
});
|
73
|
+
return hasMfeServerConfig;
|
74
|
+
}
|