@nx/module-federation 20.5.0-beta.2 → 20.5.0-beta.4

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.
Files changed (29) hide show
  1. package/package.json +7 -6
  2. package/rspack.d.ts +2 -0
  3. package/rspack.js +2 -0
  4. package/src/plugins/models/index.d.ts +14 -0
  5. package/src/plugins/models/index.js +2 -0
  6. package/src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-dev-server-plugin.d.ts +13 -0
  7. package/src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-dev-server-plugin.js +62 -0
  8. package/src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-plugin.d.ts +12 -0
  9. package/src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-plugin.js +51 -0
  10. package/src/plugins/utils/build-static-remotes.d.ts +3 -0
  11. package/src/plugins/utils/build-static-remotes.js +67 -0
  12. package/src/plugins/utils/get-dynamic-manifest-file.d.ts +2 -0
  13. package/src/plugins/utils/get-dynamic-manifest-file.js +17 -0
  14. package/src/plugins/utils/get-remotes.d.ts +7 -0
  15. package/src/plugins/utils/get-remotes.js +63 -0
  16. package/src/plugins/utils/get-static-remotes.d.ts +3 -0
  17. package/src/plugins/utils/get-static-remotes.js +26 -0
  18. package/src/plugins/utils/index.d.ts +7 -0
  19. package/src/plugins/utils/index.js +10 -0
  20. package/src/plugins/utils/parse-remotes-config.d.ts +6 -0
  21. package/src/plugins/utils/parse-remotes-config.js +30 -0
  22. package/src/plugins/utils/start-remote-proxies.d.ts +5 -0
  23. package/src/plugins/utils/start-remote-proxies.js +39 -0
  24. package/src/plugins/utils/start-static-remotes-file-server.d.ts +2 -0
  25. package/src/plugins/utils/start-static-remotes-file-server.js +43 -0
  26. package/src/with-module-federation/rspack/utils.d.ts +2 -2
  27. package/src/with-module-federation/rspack/utils.js +2 -8
  28. package/src/with-module-federation/rspack/with-module-federation-ssr.js +1 -1
  29. package/src/with-module-federation/rspack/with-module-federation.js +1 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nx/module-federation",
3
3
  "description": "The Nx Plugin for Module Federation contains executors and utilities that support building applications using Module Federation.",
4
- "version": "20.5.0-beta.2",
4
+ "version": "20.5.0-beta.4",
5
5
  "type": "commonjs",
6
6
  "repository": {
7
7
  "type": "git",
@@ -25,19 +25,20 @@
25
25
  "executors": "./executors.json",
26
26
  "dependencies": {
27
27
  "tslib": "^2.3.0",
28
- "@nx/devkit": "20.5.0-beta.2",
29
- "@nx/js": "20.5.0-beta.2",
30
- "@nx/web": "20.5.0-beta.2",
28
+ "@nx/devkit": "20.5.0-beta.4",
29
+ "@nx/js": "20.5.0-beta.4",
30
+ "@nx/web": "20.5.0-beta.4",
31
31
  "picocolors": "^1.1.0",
32
32
  "webpack": "^5.88.0",
33
- "@rspack/core": "^1.1.5",
34
33
  "@module-federation/enhanced": "^0.8.8",
35
34
  "@module-federation/node": "^2.6.21",
36
35
  "@module-federation/sdk": "^0.8.8",
37
36
  "express": "^4.21.2",
38
37
  "http-proxy-middleware": "^3.0.3"
39
38
  },
40
- "peerDependencies": {},
39
+ "peerDependencies": {
40
+ "@rspack/core": "^1.1.5"
41
+ },
41
42
  "nx-migrations": {
42
43
  "migrations": "./migrations.json"
43
44
  },
package/rspack.d.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  export * from './src/with-module-federation/rspack/with-module-federation';
2
2
  export * from './src/with-module-federation/rspack/with-module-federation-ssr';
3
+ export * from './src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-plugin';
4
+ export * from './src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-dev-server-plugin';
package/rspack.js CHANGED
@@ -3,3 +3,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  tslib_1.__exportStar(require("./src/with-module-federation/rspack/with-module-federation"), exports);
5
5
  tslib_1.__exportStar(require("./src/with-module-federation/rspack/with-module-federation-ssr"), exports);
6
+ tslib_1.__exportStar(require("./src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-plugin"), exports);
7
+ tslib_1.__exportStar(require("./src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-dev-server-plugin"), exports);
@@ -0,0 +1,14 @@
1
+ export interface NxModuleFederationDevServerConfig {
2
+ host?: string;
3
+ staticRemotesPort?: number;
4
+ pathToManifestFile?: string;
5
+ ssl?: boolean;
6
+ sslCert?: string;
7
+ sslKey?: string;
8
+ parallel?: number;
9
+ devRemoteFindOptions?: DevRemoteFindOptions;
10
+ }
11
+ export interface DevRemoteFindOptions {
12
+ retries?: number;
13
+ retryDelay?: number;
14
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,13 @@
1
+ import { Compiler, RspackPluginInstance } from '@rspack/core';
2
+ import { ModuleFederationConfig } from '../../../utils/models';
3
+ import { NxModuleFederationDevServerConfig } from '../../models';
4
+ export declare class NxModuleFederationDevServerPlugin implements RspackPluginInstance {
5
+ private _options;
6
+ private nxBin;
7
+ constructor(_options: {
8
+ config: ModuleFederationConfig;
9
+ devServerConfig: NxModuleFederationDevServerConfig;
10
+ });
11
+ apply(compiler: Compiler): void;
12
+ private setup;
13
+ }
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NxModuleFederationDevServerPlugin = void 0;
4
+ const core_1 = require("@rspack/core");
5
+ const pc = require("picocolors");
6
+ const devkit_1 = require("@nx/devkit");
7
+ const path_1 = require("path");
8
+ const fs_1 = require("fs");
9
+ const utils_1 = require("../../utils");
10
+ const PLUGIN_NAME = 'NxModuleFederationDevServerPlugin';
11
+ class NxModuleFederationDevServerPlugin {
12
+ constructor(_options) {
13
+ this._options = _options;
14
+ this.nxBin = require.resolve('nx/bin/nx');
15
+ }
16
+ apply(compiler) {
17
+ compiler.hooks.beforeCompile.tapAsync(PLUGIN_NAME, async (params, callback) => {
18
+ const staticRemotesConfig = await this.setup();
19
+ devkit_1.logger.info(`NX Starting module federation dev-server for ${pc.bold(this._options.config.name)} with ${Object.keys(staticRemotesConfig).length} remotes`);
20
+ const mappedLocationOfRemotes = await (0, utils_1.buildStaticRemotes)(staticRemotesConfig, this._options.devServerConfig, this.nxBin);
21
+ (0, utils_1.startStaticRemotesFileServer)(staticRemotesConfig, devkit_1.workspaceRoot, this._options.devServerConfig.staticRemotesPort);
22
+ (0, utils_1.startRemoteProxies)(staticRemotesConfig, mappedLocationOfRemotes, {
23
+ pathToCert: this._options.devServerConfig.sslCert,
24
+ pathToKey: this._options.devServerConfig.sslCert,
25
+ });
26
+ new core_1.DefinePlugin({
27
+ 'process.env.NX_MF_DEV_REMOTES': process.env.NX_MF_DEV_REMOTES,
28
+ }).apply(compiler);
29
+ callback();
30
+ });
31
+ }
32
+ async setup() {
33
+ const projectGraph = (0, devkit_1.readCachedProjectGraph)();
34
+ const { projects: workspaceProjects } = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
35
+ const project = workspaceProjects[this._options.config.name];
36
+ if (!this._options.devServerConfig.pathToManifestFile) {
37
+ this._options.devServerConfig.pathToManifestFile =
38
+ (0, utils_1.getDynamicMfManifestFile)(project, devkit_1.workspaceRoot);
39
+ }
40
+ else {
41
+ const userPathToManifestFile = (0, path_1.join)(devkit_1.workspaceRoot, this._options.devServerConfig.pathToManifestFile);
42
+ if (!(0, fs_1.existsSync)(userPathToManifestFile)) {
43
+ throw new Error(`The provided Module Federation manifest file path does not exist. Please check the file exists at "${userPathToManifestFile}".`);
44
+ }
45
+ else if ((0, path_1.extname)(this._options.devServerConfig.pathToManifestFile) !== '.json') {
46
+ throw new Error(`The Module Federation manifest file must be a JSON. Please ensure the file at ${userPathToManifestFile} is a JSON.`);
47
+ }
48
+ this._options.devServerConfig.pathToManifestFile = userPathToManifestFile;
49
+ }
50
+ const { remotes, staticRemotePort } = (0, utils_1.getRemotes)(this._options.config, projectGraph, this._options.devServerConfig.pathToManifestFile);
51
+ this._options.devServerConfig.staticRemotesPort ??= staticRemotePort;
52
+ const remotesConfig = (0, utils_1.parseRemotesConfig)(remotes, devkit_1.workspaceRoot, projectGraph);
53
+ const staticRemotesConfig = await (0, utils_1.getStaticRemotes)(remotesConfig.config ?? {});
54
+ const devRemotes = remotes.filter((r) => !staticRemotesConfig[r]);
55
+ process.env.NX_MF_DEV_REMOTES = JSON.stringify([
56
+ ...(devRemotes.length > 0 ? devRemotes : []),
57
+ project.name,
58
+ ]);
59
+ return staticRemotesConfig ?? {};
60
+ }
61
+ }
62
+ exports.NxModuleFederationDevServerPlugin = NxModuleFederationDevServerPlugin;
@@ -0,0 +1,12 @@
1
+ import { Compiler, RspackPluginInstance } from '@rspack/core';
2
+ import { ModuleFederationConfig, NxModuleFederationConfigOverride } from '../../../utils/models';
3
+ import { NxModuleFederationDevServerConfig } from '../../models';
4
+ export declare class NxModuleFederationPlugin implements RspackPluginInstance {
5
+ private _options;
6
+ private configOverride?;
7
+ constructor(_options: {
8
+ config: ModuleFederationConfig;
9
+ devServerConfig?: NxModuleFederationDevServerConfig;
10
+ }, configOverride?: NxModuleFederationConfigOverride);
11
+ apply(compiler: Compiler): void;
12
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NxModuleFederationPlugin = void 0;
4
+ const utils_1 = require("../../../with-module-federation/rspack/utils");
5
+ const nx_module_federation_dev_server_plugin_1 = require("./nx-module-federation-dev-server-plugin");
6
+ class NxModuleFederationPlugin {
7
+ constructor(_options, configOverride) {
8
+ this._options = _options;
9
+ this.configOverride = configOverride;
10
+ }
11
+ apply(compiler) {
12
+ if (global.NX_GRAPH_CREATION) {
13
+ return;
14
+ }
15
+ // This is required to ensure Module Federation will build the project correctly
16
+ compiler.options.optimization.runtimeChunk = false;
17
+ const isDevServer = !!process.env['WEBPACK_SERVE'];
18
+ // TODO(colum): Add support for SSR
19
+ const config = (0, utils_1.getModuleFederationConfig)(this._options.config);
20
+ const sharedLibraries = config.sharedLibraries;
21
+ const sharedDependencies = config.sharedDependencies;
22
+ const mappedRemotes = config.mappedRemotes;
23
+ new (require('@module-federation/enhanced/rspack').ModuleFederationPlugin)({
24
+ name: this._options.config.name.replace(/-/g, '_'),
25
+ filename: 'remoteEntry.js',
26
+ exposes: this._options.config.exposes,
27
+ remotes: mappedRemotes,
28
+ shared: {
29
+ ...(sharedDependencies ?? {}),
30
+ },
31
+ ...(this.configOverride ? this.configOverride : {}),
32
+ runtimePlugins: this.configOverride
33
+ ? this.configOverride.runtimePlugins ?? []
34
+ : [],
35
+ virtualRuntimeEntry: true,
36
+ }).apply(compiler);
37
+ if (sharedLibraries) {
38
+ sharedLibraries.getReplacementPlugin().apply(compiler);
39
+ }
40
+ if (isDevServer) {
41
+ new nx_module_federation_dev_server_plugin_1.NxModuleFederationDevServerPlugin({
42
+ config: this._options.config,
43
+ devServerConfig: {
44
+ ...(this._options.devServerConfig ?? {}),
45
+ host: this._options.devServerConfig?.host ?? 'localhost',
46
+ },
47
+ }).apply(compiler);
48
+ }
49
+ }
50
+ }
51
+ exports.NxModuleFederationPlugin = NxModuleFederationPlugin;
@@ -0,0 +1,3 @@
1
+ import { StaticRemoteConfig } from '../../utils';
2
+ import { NxModuleFederationDevServerConfig } from '../models';
3
+ export declare function buildStaticRemotes(staticRemotesConfig: Record<string, StaticRemoteConfig>, options: NxModuleFederationDevServerConfig, nxBin: string): Promise<Record<string, string>>;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildStaticRemotes = buildStaticRemotes;
4
+ const node_child_process_1 = require("node:child_process");
5
+ const path_1 = require("path");
6
+ const node_fs_1 = require("node:fs");
7
+ const cache_directory_1 = require("nx/src/utils/cache-directory");
8
+ const devkit_1 = require("@nx/devkit");
9
+ async function buildStaticRemotes(staticRemotesConfig, options, nxBin) {
10
+ const remotes = Object.keys(staticRemotesConfig);
11
+ if (!remotes.length) {
12
+ return;
13
+ }
14
+ const mappedLocationOfRemotes = {};
15
+ for (const app of remotes) {
16
+ mappedLocationOfRemotes[app] = `http${options.ssl ? 's' : ''}://${options.host}:${options.staticRemotesPort}/${staticRemotesConfig[app].urlSegment}`;
17
+ }
18
+ await new Promise((res, rej) => {
19
+ console.log(`NX Building ${remotes.length} static remotes...`);
20
+ const staticProcess = (0, node_child_process_1.fork)(nxBin, [
21
+ 'run-many',
22
+ `--target=build`,
23
+ `--projects=${remotes.join(',')}`,
24
+ ...(options.parallel ? [`--parallel=${options.parallel}`] : []),
25
+ ], {
26
+ cwd: devkit_1.workspaceRoot,
27
+ stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
28
+ });
29
+ // File to debug build failures e.g. 2024-01-01T00_00_0_0Z-build.log'
30
+ const remoteBuildLogFile = (0, path_1.join)(cache_directory_1.workspaceDataDirectory,
31
+ // eslint-disable-next-line
32
+ `${new Date().toISOString().replace(/[:\.]/g, '_')}-build.log`);
33
+ const stdoutStream = (0, node_fs_1.createWriteStream)(remoteBuildLogFile);
34
+ staticProcess.stdout?.on('data', (data) => {
35
+ const ANSII_CODE_REGEX =
36
+ // eslint-disable-next-line no-control-regex
37
+ /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
38
+ const stdoutString = data.toString().replace(ANSII_CODE_REGEX, '');
39
+ stdoutStream.write(stdoutString);
40
+ // in addition to writing into the stdout stream, also show error directly in console
41
+ // so the error is easily discoverable. 'ERROR in' is the key word to search in webpack output.
42
+ if (stdoutString.includes('ERROR in')) {
43
+ console.log(stdoutString);
44
+ }
45
+ if (stdoutString.includes('Successfully ran target build')) {
46
+ staticProcess.stdout?.removeAllListeners('data');
47
+ console.info(`NX Built ${remotes.length} static remotes`);
48
+ res();
49
+ }
50
+ });
51
+ staticProcess.stderr?.on('data', (data) => console.log(data.toString()));
52
+ staticProcess.once('exit', (code) => {
53
+ stdoutStream.end();
54
+ staticProcess.stdout?.removeAllListeners('data');
55
+ staticProcess.stderr?.removeAllListeners('data');
56
+ if (code !== 0) {
57
+ rej(`Remote failed to start. A complete log can be found in: ${remoteBuildLogFile}`);
58
+ }
59
+ else {
60
+ res();
61
+ }
62
+ });
63
+ process.on('SIGTERM', () => staticProcess.kill('SIGTERM'));
64
+ process.on('exit', () => staticProcess.kill('SIGTERM'));
65
+ });
66
+ return mappedLocationOfRemotes;
67
+ }
@@ -0,0 +1,2 @@
1
+ import { type ProjectConfiguration } from '@nx/devkit';
2
+ export declare function getDynamicMfManifestFile(project: ProjectConfiguration, workspaceRoot: string): string | undefined;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDynamicMfManifestFile = getDynamicMfManifestFile;
4
+ const path_1 = require("path");
5
+ const fs_1 = require("fs");
6
+ function getDynamicMfManifestFile(project, workspaceRoot) {
7
+ // {sourceRoot}/assets/module-federation.manifest.json was the generated
8
+ // path for the manifest file in the past. We now generate the manifest
9
+ // file at {root}/public/module-federation.manifest.json. This check
10
+ // ensures that we can still support the old path for backwards
11
+ // compatibility since old projects may still have the manifest file
12
+ // at the old path.
13
+ return [
14
+ (0, path_1.join)(workspaceRoot, project.root, 'public/module-federation.manifest.json'),
15
+ (0, path_1.join)(workspaceRoot, project.sourceRoot, 'assets/module-federation.manifest.json'),
16
+ ].find((path) => (0, fs_1.existsSync)(path));
17
+ }
@@ -0,0 +1,7 @@
1
+ import { ProjectGraph } from '@nx/devkit';
2
+ import { ModuleFederationConfig } from '../../utils';
3
+ export declare function getRemotes(config: ModuleFederationConfig, projectGraph: ProjectGraph, pathToManifestFile?: string): {
4
+ remotes: string[];
5
+ remotePorts: any[];
6
+ staticRemotePort: number;
7
+ };
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRemotes = getRemotes;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const utils_1 = require("../../utils");
6
+ const fs_1 = require("fs");
7
+ const path_1 = require("path");
8
+ function getRemotes(config, projectGraph, pathToManifestFile) {
9
+ const collectedRemotes = new Set();
10
+ const { remotes, dynamicRemotes } = extractRemoteProjectsFromConfig(config, pathToManifestFile);
11
+ remotes.forEach((r) => collectRemoteProjects(r, collectedRemotes, projectGraph));
12
+ // With dynamic remotes, the manifest file may contain the names with `_` due to MF limitations on naming
13
+ // The project graph might contain these names with `-` rather than `_`. Check for both.
14
+ // This can occur after migration of existing remotes past Nx 19.8
15
+ let normalizedDynamicRemotes = dynamicRemotes.map((r) => {
16
+ if (projectGraph.nodes[r.replace(/_/g, '-')]) {
17
+ return r.replace(/_/g, '-');
18
+ }
19
+ return r;
20
+ });
21
+ const knownDynamicRemotes = normalizedDynamicRemotes.filter((r) => projectGraph.nodes[r]);
22
+ const remotePorts = [...collectedRemotes, ...knownDynamicRemotes].map((r) => projectGraph.nodes[r].data.targets['serve'].options.port);
23
+ const staticRemotePort = Math.max(...[...remotePorts]) + 1;
24
+ return {
25
+ remotes: Array.from(collectedRemotes),
26
+ remotePorts,
27
+ staticRemotePort,
28
+ };
29
+ }
30
+ function extractRemoteProjectsFromConfig(config, pathToManifestFile) {
31
+ const remotes = [];
32
+ const dynamicRemotes = [];
33
+ if (pathToManifestFile && (0, fs_1.existsSync)(pathToManifestFile)) {
34
+ const moduleFederationManifestJson = (0, fs_1.readFileSync)(pathToManifestFile, 'utf-8');
35
+ if (moduleFederationManifestJson) {
36
+ // This should have shape of
37
+ // {
38
+ // "remoteName": "remoteLocation",
39
+ // }
40
+ const parsedManifest = JSON.parse(moduleFederationManifestJson);
41
+ if (Object.keys(parsedManifest).every((key) => typeof key === 'string' && typeof parsedManifest[key] === 'string')) {
42
+ dynamicRemotes.push(...Object.keys(parsedManifest));
43
+ }
44
+ }
45
+ }
46
+ const staticRemotes = config.remotes?.map((r) => (Array.isArray(r) ? r[0] : r)) ?? [];
47
+ remotes.push(...staticRemotes);
48
+ return { remotes, dynamicRemotes };
49
+ }
50
+ function collectRemoteProjects(remote, collected, projectGraph) {
51
+ const remoteProject = projectGraph.nodes[remote]?.data;
52
+ if (!projectGraph.nodes[remote] || collected.has(remote)) {
53
+ return;
54
+ }
55
+ collected.add(remote);
56
+ const remoteProjectRoot = remoteProject.root;
57
+ let remoteProjectTsConfig = ['tsconfig.app.json', 'tsconfig.json']
58
+ .map((p) => (0, path_1.join)(devkit_1.workspaceRoot, remoteProjectRoot, p))
59
+ .find((p) => (0, fs_1.existsSync)(p));
60
+ const remoteProjectConfig = (0, utils_1.getModuleFederationConfig)(remoteProjectTsConfig, devkit_1.workspaceRoot, remoteProjectRoot);
61
+ const { remotes: remoteProjectRemotes } = extractRemoteProjectsFromConfig(remoteProjectConfig);
62
+ remoteProjectRemotes.forEach((r) => collectRemoteProjects(r, collected, projectGraph));
63
+ }
@@ -0,0 +1,3 @@
1
+ import { StaticRemoteConfig } from '../../utils';
2
+ import { DevRemoteFindOptions } from '../models';
3
+ export declare function getStaticRemotes(remotesConfig: Record<string, StaticRemoteConfig>, devRemoteFindOptions?: DevRemoteFindOptions): Promise<Record<string, StaticRemoteConfig>>;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getStaticRemotes = getStaticRemotes;
4
+ const wait_for_port_open_1 = require("@nx/web/src/utils/wait-for-port-open");
5
+ async function getStaticRemotes(remotesConfig, devRemoteFindOptions) {
6
+ const remotes = Object.keys(remotesConfig);
7
+ const findStaticRemotesPromises = [];
8
+ for (const remote of remotes) {
9
+ findStaticRemotesPromises.push(new Promise((resolve, reject) => {
10
+ (0, wait_for_port_open_1.waitForPortOpen)(remotesConfig[remote].port, {
11
+ retries: devRemoteFindOptions?.retries ?? 3,
12
+ retryDelay: devRemoteFindOptions?.retryDelay ?? 1000,
13
+ }).then((res) => {
14
+ resolve(undefined);
15
+ }, (rej) => {
16
+ resolve(remote);
17
+ });
18
+ }));
19
+ }
20
+ const staticRemoteNames = (await Promise.all(findStaticRemotesPromises)).filter(Boolean);
21
+ let staticRemotesConfig = {};
22
+ for (const remote of staticRemoteNames) {
23
+ staticRemotesConfig[remote] = remotesConfig[remote];
24
+ }
25
+ return staticRemotesConfig;
26
+ }
@@ -0,0 +1,7 @@
1
+ export * from './build-static-remotes';
2
+ export * from './get-dynamic-manifest-file';
3
+ export * from './get-remotes';
4
+ export * from './get-static-remotes';
5
+ export * from './parse-remotes-config';
6
+ export * from './start-remote-proxies';
7
+ export * from './start-static-remotes-file-server';
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./build-static-remotes"), exports);
5
+ tslib_1.__exportStar(require("./get-dynamic-manifest-file"), exports);
6
+ tslib_1.__exportStar(require("./get-remotes"), exports);
7
+ tslib_1.__exportStar(require("./get-static-remotes"), exports);
8
+ tslib_1.__exportStar(require("./parse-remotes-config"), exports);
9
+ tslib_1.__exportStar(require("./start-remote-proxies"), exports);
10
+ tslib_1.__exportStar(require("./start-static-remotes-file-server"), exports);
@@ -0,0 +1,6 @@
1
+ import { ProjectGraph } from '@nx/devkit';
2
+ import { StaticRemoteConfig } from '../../utils';
3
+ export declare function parseRemotesConfig(remotes: string[] | undefined, workspaceRoot: string, projectGraph: ProjectGraph): {
4
+ remotes: string[];
5
+ config: Record<string, StaticRemoteConfig>;
6
+ };
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseRemotesConfig = parseRemotesConfig;
4
+ const path_1 = require("path");
5
+ const devkit_internals_1 = require("nx/src/devkit-internals");
6
+ const devkit_1 = require("@nx/devkit");
7
+ function parseRemotesConfig(remotes, workspaceRoot, projectGraph) {
8
+ if (!remotes?.length) {
9
+ return { remotes: [], config: undefined };
10
+ }
11
+ const config = {};
12
+ for (const app of remotes) {
13
+ const projectRoot = projectGraph.nodes[app].data.root;
14
+ let outputPath = (0, devkit_internals_1.interpolate)(projectGraph.nodes[app].data.targets?.['build']?.options?.outputPath ??
15
+ projectGraph.nodes[app].data.targets?.['build']?.outputs?.[0] ??
16
+ `${workspaceRoot ? `${workspaceRoot}/` : ''}${projectGraph.nodes[app].data.root}/dist`, {
17
+ projectName: projectGraph.nodes[app].data.name,
18
+ projectRoot,
19
+ workspaceRoot,
20
+ });
21
+ if (outputPath.startsWith(projectRoot)) {
22
+ outputPath = (0, devkit_1.joinPathFragments)(workspaceRoot, outputPath);
23
+ }
24
+ const basePath = (0, path_1.dirname)(outputPath);
25
+ const urlSegment = app;
26
+ const port = projectGraph.nodes[app].data.targets?.['serve']?.options.port;
27
+ config[app] = { basePath, outputPath, urlSegment, port };
28
+ }
29
+ return { remotes, config };
30
+ }
@@ -0,0 +1,5 @@
1
+ import { StaticRemoteConfig } from '../../utils';
2
+ export declare function startRemoteProxies(staticRemotesConfig: Record<string, StaticRemoteConfig>, mappedLocationsOfRemotes: Record<string, string>, sslOptions?: {
3
+ pathToCert: string;
4
+ pathToKey: string;
5
+ }): void;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startRemoteProxies = startRemoteProxies;
4
+ const fs_1 = require("fs");
5
+ function startRemoteProxies(staticRemotesConfig, mappedLocationsOfRemotes, sslOptions) {
6
+ const { createProxyMiddleware } = require('http-proxy-middleware');
7
+ const express = require('express');
8
+ let sslCert;
9
+ let sslKey;
10
+ if (sslOptions && sslOptions.pathToCert && sslOptions.pathToKey) {
11
+ if ((0, fs_1.existsSync)(sslOptions.pathToCert) && (0, fs_1.existsSync)(sslOptions.pathToKey)) {
12
+ sslCert = (0, fs_1.readFileSync)(sslOptions.pathToCert);
13
+ sslKey = (0, fs_1.readFileSync)(sslOptions.pathToKey);
14
+ }
15
+ else {
16
+ console.warn(`Encountered SSL options in project.json, however, the certificate files do not exist in the filesystem. Using http.`);
17
+ console.warn(`Attempted to find '${sslOptions.pathToCert}' and '${sslOptions.pathToKey}'.`);
18
+ }
19
+ }
20
+ const http = require('http');
21
+ const https = require('https');
22
+ const remotes = Object.keys(staticRemotesConfig);
23
+ console.log(`NX Starting static remotes proxies...`);
24
+ for (const app of remotes) {
25
+ const appConfig = staticRemotesConfig[app];
26
+ const expressProxy = express();
27
+ expressProxy.use(createProxyMiddleware({
28
+ target: mappedLocationsOfRemotes[app],
29
+ changeOrigin: true,
30
+ secure: sslCert ? false : undefined,
31
+ }));
32
+ const proxyServer = (sslCert ? https : http)
33
+ .createServer({ cert: sslCert, key: sslKey }, expressProxy)
34
+ .listen(appConfig.port);
35
+ process.on('SIGTERM', () => proxyServer.close());
36
+ process.on('exit', () => proxyServer.close());
37
+ }
38
+ console.info(`NX Static remotes proxies started successfully`);
39
+ }
@@ -0,0 +1,2 @@
1
+ import { StaticRemoteConfig } from '../../utils';
2
+ export declare function startStaticRemotesFileServer(staticRemotesConfig: Record<string, StaticRemoteConfig>, root: string, staticRemotesPort: number): void;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startStaticRemotesFileServer = startStaticRemotesFileServer;
4
+ const path_1 = require("path");
5
+ const fs_1 = require("fs");
6
+ const node_child_process_1 = require("node:child_process");
7
+ const devkit_1 = require("@nx/devkit");
8
+ const devkit_internals_1 = require("nx/src/devkit-internals");
9
+ function startStaticRemotesFileServer(staticRemotesConfig, root, staticRemotesPort) {
10
+ const remotes = Object.keys(staticRemotesConfig);
11
+ if (!remotes || remotes.length === 0) {
12
+ return;
13
+ }
14
+ let shouldMoveToCommonLocation = false;
15
+ const commonOutputDirectory = (0, path_1.join)(devkit_1.workspaceRoot, 'tmp/static-remotes');
16
+ for (const app of remotes) {
17
+ const remoteConfig = staticRemotesConfig[app];
18
+ if (remoteConfig) {
19
+ (0, fs_1.cpSync)(remoteConfig.outputPath, (0, path_1.join)(commonOutputDirectory, remoteConfig.urlSegment), {
20
+ force: true,
21
+ recursive: true,
22
+ });
23
+ }
24
+ }
25
+ const { path: pathToHttpServerPkgJson, packageJson } = (0, devkit_internals_1.readModulePackageJson)('http-server', module.paths);
26
+ const pathToHttpServerBin = packageJson.bin['http-server'];
27
+ const pathToHttpServer = (0, path_1.resolve)(pathToHttpServerPkgJson.replace('package.json', ''), pathToHttpServerBin);
28
+ const httpServerProcess = (0, node_child_process_1.fork)(pathToHttpServer, [
29
+ commonOutputDirectory,
30
+ `-p=${staticRemotesPort}`,
31
+ `-a=localhost`,
32
+ `--cors`,
33
+ ], {
34
+ stdio: 'pipe',
35
+ cwd: root,
36
+ env: {
37
+ FORCE_COLOR: 'true',
38
+ ...process.env,
39
+ },
40
+ });
41
+ process.on('SIGTERM', () => httpServerProcess.kill('SIGTERM'));
42
+ process.on('exit', () => httpServerProcess.kill('SIGTERM'));
43
+ }
@@ -3,10 +3,10 @@ export declare function getFunctionDeterminateRemoteUrl(isServer?: boolean): (re
3
3
  export declare function getModuleFederationConfig(mfConfig: ModuleFederationConfig, options?: {
4
4
  isServer: boolean;
5
5
  determineRemoteUrl?: (remote: string) => string;
6
- }): Promise<{
6
+ }): {
7
7
  sharedLibraries: import("../../utils").SharedWorkspaceLibraryConfig;
8
8
  sharedDependencies: {
9
9
  [x: string]: import("../../utils").SharedLibraryConfig;
10
10
  };
11
11
  mappedRemotes: {};
12
- }>;
12
+ };
@@ -34,14 +34,8 @@ function getFunctionDeterminateRemoteUrl(isServer = false) {
34
34
  return `${host.endsWith('/') ? host.slice(0, -1) : host}:${port}/${remoteEntry}`;
35
35
  };
36
36
  }
37
- async function getModuleFederationConfig(mfConfig, options = { isServer: false }) {
38
- let projectGraph;
39
- try {
40
- projectGraph = (0, devkit_1.readCachedProjectGraph)();
41
- }
42
- catch (e) {
43
- projectGraph = await (0, devkit_1.createProjectGraphAsync)();
44
- }
37
+ function getModuleFederationConfig(mfConfig, options = { isServer: false }) {
38
+ const projectGraph = (0, devkit_1.readCachedProjectGraph)();
45
39
  const project = projectGraph.nodes[mfConfig.name]?.data;
46
40
  if (!project) {
47
41
  throw Error(`Cannot find project "${mfConfig.name}". Check that the name is correct in module-federation.config.js`);
@@ -7,7 +7,7 @@ async function withModuleFederationForSSR(options, configOverride) {
7
7
  if (global.NX_GRAPH_CREATION) {
8
8
  return (config) => config;
9
9
  }
10
- const { sharedLibraries, sharedDependencies, mappedRemotes } = await (0, utils_1.getModuleFederationConfig)(options, {
10
+ const { sharedLibraries, sharedDependencies, mappedRemotes } = (0, utils_1.getModuleFederationConfig)(options, {
11
11
  isServer: true,
12
12
  });
13
13
  return (config, { context }) => {
@@ -15,7 +15,7 @@ async function withModuleFederation(options, configOverride) {
15
15
  return config;
16
16
  };
17
17
  }
18
- const { sharedDependencies, sharedLibraries, mappedRemotes } = await (0, utils_1.getModuleFederationConfig)(options);
18
+ const { sharedDependencies, sharedLibraries, mappedRemotes } = (0, utils_1.getModuleFederationConfig)(options);
19
19
  const isGlobal = isVarOrWindow(options.library?.type);
20
20
  return function makeConfig(config, { context }) {
21
21
  config.output.uniqueName = options.name;