@nx/module-federation 21.2.1 → 21.2.3

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 CHANGED
@@ -23,21 +23,40 @@
23
23
  },
24
24
  "20.5.0": {
25
25
  "version": "20.5.0-beta.5",
26
- "@module-federation/enhanced": {
27
- "version": "^0.9.0",
28
- "alwaysAddToPackageJson": false
29
- },
30
- "@module-federation/runtime": {
31
- "version": "^0.9.0",
32
- "alwaysAddToPackageJson": false
33
- },
34
- "@module-federation/sdk": {
35
- "version": "^0.9.0",
36
- "alwaysAddToPackageJson": false
37
- },
38
- "@module-federation/node": {
39
- "version": "^2.6.26",
40
- "alwaysAddToPackageJson": false
26
+ "packages": {
27
+ "@module-federation/enhanced": {
28
+ "version": "^0.9.0",
29
+ "alwaysAddToPackageJson": false
30
+ },
31
+ "@module-federation/runtime": {
32
+ "version": "^0.9.0",
33
+ "alwaysAddToPackageJson": false
34
+ },
35
+ "@module-federation/sdk": {
36
+ "version": "^0.9.0",
37
+ "alwaysAddToPackageJson": false
38
+ },
39
+ "@module-federation/node": {
40
+ "version": "^2.6.26",
41
+ "alwaysAddToPackageJson": false
42
+ }
43
+ }
44
+ },
45
+ "21.2.0": {
46
+ "version": "21.2.0-beta.6",
47
+ "packages": {
48
+ "@module-federation/enhanced": {
49
+ "version": "^0.15.0",
50
+ "alwaysAddToPackageJson": false
51
+ },
52
+ "@module-federation/runtime": {
53
+ "version": "^0.15.0",
54
+ "alwaysAddToPackageJson": false
55
+ },
56
+ "@module-federation/sdk": {
57
+ "version": "^0.15.0",
58
+ "alwaysAddToPackageJson": false
59
+ }
41
60
  }
42
61
  }
43
62
  }
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": "21.2.1",
4
+ "version": "21.2.3",
5
5
  "type": "commonjs",
6
6
  "repository": {
7
7
  "type": "git",
@@ -25,15 +25,15 @@
25
25
  "executors": "./executors.json",
26
26
  "dependencies": {
27
27
  "tslib": "^2.3.0",
28
- "@nx/devkit": "21.2.1",
29
- "@nx/js": "21.2.1",
30
- "@nx/web": "21.2.1",
28
+ "@nx/devkit": "21.2.3",
29
+ "@nx/js": "21.2.3",
30
+ "@nx/web": "21.2.3",
31
31
  "picocolors": "^1.1.0",
32
32
  "webpack": "^5.88.0",
33
33
  "@rspack/core": "^1.3.8",
34
- "@module-federation/enhanced": "^0.9.0",
34
+ "@module-federation/enhanced": "^0.15.0",
35
35
  "@module-federation/node": "^2.6.26",
36
- "@module-federation/sdk": "^0.9.0",
36
+ "@module-federation/sdk": "^0.15.0",
37
37
  "express": "^4.21.2",
38
38
  "http-proxy-middleware": "^3.0.3"
39
39
  },
@@ -27,6 +27,11 @@ async function buildStaticRemotes(staticRemotesConfig, nxBin, context, options,
27
27
  ], {
28
28
  cwd: context.root,
29
29
  stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
30
+ env: {
31
+ ...process.env,
32
+ // Ensure that webpack serve env var is not passed to static remotes
33
+ WEBPACK_SERVE: 'false',
34
+ },
30
35
  });
31
36
  // File to debug build failures e.g. 2024-01-01T00_00_0_0Z-build.log'
32
37
  const remoteBuildLogFile = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, `${new Date().toISOString().replace(/[:\.]/g, '_')}-build.log`);
@@ -48,7 +48,9 @@ class NxModuleFederationDevServerPlugin {
48
48
  (0, utils_1.getDynamicMfManifestFile)(project, devkit_1.workspaceRoot);
49
49
  }
50
50
  else {
51
- const userPathToManifestFile = (0, path_1.join)(devkit_1.workspaceRoot, this._options.devServerConfig.pathToManifestFile);
51
+ const userPathToManifestFile = this._options.devServerConfig.pathToManifestFile.startsWith(devkit_1.workspaceRoot)
52
+ ? this._options.devServerConfig.pathToManifestFile
53
+ : (0, path_1.join)(devkit_1.workspaceRoot, this._options.devServerConfig.pathToManifestFile);
52
54
  if (!(0, fs_1.existsSync)(userPathToManifestFile)) {
53
55
  throw new Error(`The provided Module Federation manifest file path does not exist. Please check the file exists at "${userPathToManifestFile}".`);
54
56
  }
@@ -48,7 +48,9 @@ class NxModuleFederationDevServerPlugin {
48
48
  (0, utils_1.getDynamicMfManifestFile)(project, devkit_1.workspaceRoot);
49
49
  }
50
50
  else {
51
- const userPathToManifestFile = (0, path_1.join)(devkit_1.workspaceRoot, this._options.devServerConfig.pathToManifestFile);
51
+ const userPathToManifestFile = this._options.devServerConfig.pathToManifestFile.startsWith(devkit_1.workspaceRoot)
52
+ ? this._options.devServerConfig.pathToManifestFile
53
+ : (0, path_1.join)(devkit_1.workspaceRoot, this._options.devServerConfig.pathToManifestFile);
52
54
  if (!(0, fs_1.existsSync)(userPathToManifestFile)) {
53
55
  throw new Error(`The provided Module Federation manifest file path does not exist. Please check the file exists at "${userPathToManifestFile}".`);
54
56
  }
@@ -25,6 +25,10 @@ async function buildStaticRemotes(staticRemotesConfig, options, nxBin) {
25
25
  ], {
26
26
  cwd: devkit_1.workspaceRoot,
27
27
  stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
28
+ env: {
29
+ ...process.env,
30
+ WEBPACK_SERVE: 'false',
31
+ },
28
32
  });
29
33
  // File to debug build failures e.g. 2024-01-01T00_00_0_0Z-build.log'
30
34
  const remoteBuildLogFile = (0, path_1.join)(cache_directory_1.workspaceDataDirectory,
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getDynamicMfManifestFile = getDynamicMfManifestFile;
4
- const path_1 = require("path");
4
+ const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
5
5
  const fs_1 = require("fs");
6
+ const path_1 = require("path");
6
7
  function getDynamicMfManifestFile(project, workspaceRoot) {
7
8
  // {sourceRoot}/assets/module-federation.manifest.json was the generated
8
9
  // path for the manifest file in the past. We now generate the manifest
@@ -12,6 +13,6 @@ function getDynamicMfManifestFile(project, workspaceRoot) {
12
13
  // at the old path.
13
14
  return [
14
15
  (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
+ (0, path_1.join)(workspaceRoot, (0, ts_solution_setup_1.getProjectSourceRoot)(project), 'assets/module-federation.manifest.json'),
16
17
  ].find((path) => (0, fs_1.existsSync)(path));
17
18
  }
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getDependentPackagesForProject = getDependentPackagesForProject;
4
- const typescript_1 = require("./typescript");
5
4
  const devkit_1 = require("@nx/devkit");
5
+ const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
6
+ const typescript_1 = require("./typescript");
6
7
  function getDependentPackagesForProject(projectGraph, name) {
7
8
  const { npmPackages, workspaceLibraries } = collectDependencies(projectGraph, name);
8
9
  return {
@@ -39,7 +40,7 @@ function getLibraryImportPath(library, projectGraph) {
39
40
  buildLibsFromSource = process.env.NX_BUILD_LIBS_FROM_SOURCE === 'true';
40
41
  }
41
42
  const libraryNode = projectGraph.nodes[library];
42
- let sourceRoots = [libraryNode.data.sourceRoot];
43
+ let sourceRoots = [(0, ts_solution_setup_1.getProjectSourceRoot)(libraryNode.data)];
43
44
  if (!buildLibsFromSource && process.env.NX_BUILD_TARGET) {
44
45
  const buildTarget = (0, devkit_1.parseTargetString)(process.env.NX_BUILD_TARGET, projectGraph);
45
46
  sourceRoots = (0, devkit_1.getOutputsForTargetAndConfiguration)(buildTarget, {}, libraryNode);
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.mapRemotes = mapRemotes;
4
4
  exports.mapRemotesForSSR = mapRemotesForSSR;
5
- const path_1 = require("path");
5
+ const url_helpers_1 = require("./url-helpers");
6
6
  /**
7
7
  * Map remote names to a format that can be understood and used by Module
8
8
  * Federation.
@@ -29,19 +29,11 @@ function mapRemotes(remotes, remoteEntryExt, determineRemoteUrl, isRemoteGlobal
29
29
  function handleArrayRemote(remote, remoteEntryExt, isRemoteGlobal) {
30
30
  const [nxRemoteProjectName, remoteLocation] = remote;
31
31
  const mfRemoteName = normalizeRemoteName(nxRemoteProjectName);
32
- // Remote string starts like "promise new Promise(...)" – return as-is
32
+ const finalRemoteUrl = (0, url_helpers_1.processRemoteLocation)(remoteLocation, remoteEntryExt);
33
+ // Promise-based remotes should not use the global prefix format
33
34
  if (remoteLocation.startsWith('promise new Promise')) {
34
- return remoteLocation;
35
+ return finalRemoteUrl;
35
36
  }
36
- const resolvedUrl = new URL(remoteLocation);
37
- const ext = (0, path_1.extname)(resolvedUrl.pathname);
38
- const needsRemoteEntry = !['.js', '.mjs', '.json'].includes(ext);
39
- if (needsRemoteEntry) {
40
- resolvedUrl.pathname = resolvedUrl.pathname.endsWith('/')
41
- ? `${resolvedUrl.pathname}remoteEntry.${remoteEntryExt}`
42
- : `${resolvedUrl.pathname}/remoteEntry.${remoteEntryExt}`;
43
- }
44
- const finalRemoteUrl = resolvedUrl.href;
45
37
  return isRemoteGlobal ? `${mfRemoteName}@${finalRemoteUrl}` : finalRemoteUrl;
46
38
  }
47
39
  // Helper function to deal with remotes that are strings
@@ -65,16 +57,14 @@ function mapRemotesForSSR(remotes, remoteEntryExt, determineRemoteUrl) {
65
57
  if (Array.isArray(remote)) {
66
58
  let [nxRemoteProjectName, remoteLocation] = remote;
67
59
  const mfRemoteName = normalizeRemoteName(nxRemoteProjectName);
68
- const resolvedUrl = new URL(remoteLocation);
69
- const remoteLocationExt = (0, path_1.extname)(resolvedUrl.pathname);
70
- const needsRemoteEntry = !['.js', '.mjs', '.json'].includes(remoteLocationExt);
71
- if (needsRemoteEntry) {
72
- resolvedUrl.pathname = resolvedUrl.pathname.endsWith('/')
73
- ? `${resolvedUrl.pathname}remoteEntry.${remoteEntryExt}`
74
- : `${resolvedUrl.pathname}/remoteEntry.${remoteEntryExt}`;
60
+ const finalRemoteUrl = (0, url_helpers_1.processRemoteLocation)(remoteLocation, remoteEntryExt);
61
+ // Promise-based remotes should not use the global prefix format
62
+ if (remoteLocation.startsWith('promise new Promise')) {
63
+ mappedRemotes[mfRemoteName] = finalRemoteUrl;
64
+ }
65
+ else {
66
+ mappedRemotes[mfRemoteName] = `${mfRemoteName}@${finalRemoteUrl}`;
75
67
  }
76
- const finalRemoteUrl = resolvedUrl.href;
77
- mappedRemotes[mfRemoteName] = `${mfRemoteName}@${finalRemoteUrl}`;
78
68
  }
79
69
  else if (typeof remote === 'string') {
80
70
  const mfRemoteName = normalizeRemoteName(remote);
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Checks if a URL string is absolute (has protocol)
3
+ */
4
+ export declare function isAbsoluteUrl(url: string): boolean;
5
+ /**
6
+ * Safely processes remote locations, handling both relative and absolute URLs
7
+ * while preserving query parameters and hash fragments for absolute URLs
8
+ */
9
+ export declare function processRemoteLocation(remoteLocation: string, remoteEntryExt: 'js' | 'mjs'): string;
10
+ /**
11
+ * Processes remote URLs for runtime environments, resolving relative URLs against window.location.origin
12
+ */
13
+ export declare function processRuntimeRemoteUrl(remoteUrl: string, remoteEntryExt: 'js' | 'mjs'): string;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isAbsoluteUrl = isAbsoluteUrl;
4
+ exports.processRemoteLocation = processRemoteLocation;
5
+ exports.processRuntimeRemoteUrl = processRuntimeRemoteUrl;
6
+ const path_1 = require("path");
7
+ /**
8
+ * Checks if a URL string is absolute (has protocol)
9
+ */
10
+ function isAbsoluteUrl(url) {
11
+ try {
12
+ new URL(url);
13
+ return true;
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ }
19
+ /**
20
+ * Safely processes remote locations, handling both relative and absolute URLs
21
+ * while preserving query parameters and hash fragments for absolute URLs
22
+ */
23
+ function processRemoteLocation(remoteLocation, remoteEntryExt) {
24
+ // Handle promise-based remotes as-is
25
+ if (remoteLocation.startsWith('promise new Promise')) {
26
+ return remoteLocation;
27
+ }
28
+ if (isAbsoluteUrl(remoteLocation)) {
29
+ // Use new URL parsing for absolute URLs (supports query params/hash)
30
+ const url = new URL(remoteLocation);
31
+ const ext = (0, path_1.extname)(url.pathname);
32
+ const needsRemoteEntry = !['.js', '.mjs', '.json'].includes(ext);
33
+ if (needsRemoteEntry) {
34
+ url.pathname = url.pathname.endsWith('/')
35
+ ? `${url.pathname}remoteEntry.${remoteEntryExt}`
36
+ : `${url.pathname}/remoteEntry.${remoteEntryExt}`;
37
+ }
38
+ return url.href;
39
+ }
40
+ else {
41
+ // Use string manipulation for relative URLs (backward compatibility)
42
+ const ext = (0, path_1.extname)(remoteLocation);
43
+ const needsRemoteEntry = !['.js', '.mjs', '.json'].includes(ext);
44
+ if (needsRemoteEntry) {
45
+ const baseRemote = remoteLocation.endsWith('/')
46
+ ? remoteLocation.slice(0, -1)
47
+ : remoteLocation;
48
+ return `${baseRemote}/remoteEntry.${remoteEntryExt}`;
49
+ }
50
+ return remoteLocation;
51
+ }
52
+ }
53
+ /**
54
+ * Processes remote URLs for runtime environments, resolving relative URLs against window.location.origin
55
+ */
56
+ function processRuntimeRemoteUrl(remoteUrl, remoteEntryExt) {
57
+ if (isAbsoluteUrl(remoteUrl)) {
58
+ return processRemoteLocation(remoteUrl, remoteEntryExt);
59
+ }
60
+ else {
61
+ // For runtime relative URLs, resolve against current origin
62
+ const baseUrl = typeof globalThis !== 'undefined' &&
63
+ typeof globalThis.window !== 'undefined' &&
64
+ globalThis.window.location
65
+ ? globalThis.window.location.origin
66
+ : 'http://localhost';
67
+ const absoluteUrl = new URL(remoteUrl, baseUrl).href;
68
+ return processRemoteLocation(absoluteUrl, remoteEntryExt);
69
+ }
70
+ }
@@ -19,7 +19,7 @@ async function withModuleFederation(options, configOverride) {
19
19
  },
20
20
  optimization: {
21
21
  ...(config.optimization ?? {}),
22
- runtimeChunk: isDevServer
22
+ runtimeChunk: isDevServer && !options.exposes
23
23
  ? config.optimization?.runtimeChunk ?? undefined
24
24
  : false,
25
25
  },
@@ -26,7 +26,7 @@ async function withModuleFederation(options, configOverride) {
26
26
  }
27
27
  config.optimization = {
28
28
  ...(config.optimization ?? {}),
29
- runtimeChunk: isDevServer
29
+ runtimeChunk: isDevServer && !options.exposes
30
30
  ? config.optimization?.runtimeChunk ?? undefined
31
31
  : false,
32
32
  };
@@ -18,7 +18,7 @@ async function withModuleFederation(options, configOverride) {
18
18
  config.output.scriptType = 'text/javascript';
19
19
  config.optimization = {
20
20
  ...(config.optimization ?? {}),
21
- runtimeChunk: isDevServer
21
+ runtimeChunk: isDevServer && !options.exposes
22
22
  ? config.optimization?.runtimeChunk ?? undefined
23
23
  : false,
24
24
  };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Checks if a URL string is absolute (has protocol)
3
+ */
4
+ export declare function isAbsoluteUrl(url: string): boolean;
5
+ /**
6
+ * Safely processes remote locations, handling both relative and absolute URLs
7
+ * while preserving query parameters and hash fragments for absolute URLs
8
+ */
9
+ export declare function processRemoteLocation(remoteLocation: string, remoteEntryExt: 'js' | 'mjs'): string;
10
+ /**
11
+ * Processes remote URLs for runtime environments, resolving relative URLs against window.location.origin
12
+ */
13
+ export declare function processRuntimeRemoteUrl(remoteUrl: string, remoteEntryExt: 'js' | 'mjs'): string;
package/url-helpers.js ADDED
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isAbsoluteUrl = isAbsoluteUrl;
4
+ exports.processRemoteLocation = processRemoteLocation;
5
+ exports.processRuntimeRemoteUrl = processRuntimeRemoteUrl;
6
+ // Browser-safe helper function to extract file extension from a path
7
+ function extname(path) {
8
+ const lastDot = path.lastIndexOf('.');
9
+ const lastSlash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
10
+ if (lastDot === -1 || lastDot < lastSlash) {
11
+ return '';
12
+ }
13
+ return path.slice(lastDot);
14
+ }
15
+ /**
16
+ * Checks if a URL string is absolute (has protocol)
17
+ */
18
+ function isAbsoluteUrl(url) {
19
+ try {
20
+ new URL(url);
21
+ return true;
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ }
27
+ /**
28
+ * Safely processes remote locations, handling both relative and absolute URLs
29
+ * while preserving query parameters and hash fragments for absolute URLs
30
+ */
31
+ function processRemoteLocation(remoteLocation, remoteEntryExt) {
32
+ // Handle promise-based remotes as-is
33
+ if (remoteLocation.startsWith('promise new Promise')) {
34
+ return remoteLocation;
35
+ }
36
+ if (isAbsoluteUrl(remoteLocation)) {
37
+ // Use new URL parsing for absolute URLs (supports query params/hash)
38
+ const url = new URL(remoteLocation);
39
+ const ext = extname(url.pathname);
40
+ const needsRemoteEntry = !['.js', '.mjs', '.json'].includes(ext);
41
+ if (needsRemoteEntry) {
42
+ url.pathname = url.pathname.endsWith('/')
43
+ ? `${url.pathname}remoteEntry.${remoteEntryExt}`
44
+ : `${url.pathname}/remoteEntry.${remoteEntryExt}`;
45
+ }
46
+ return url.href;
47
+ }
48
+ else {
49
+ // Use string manipulation for relative URLs (backward compatibility)
50
+ const ext = extname(remoteLocation);
51
+ const needsRemoteEntry = !['.js', '.mjs', '.json'].includes(ext);
52
+ if (needsRemoteEntry) {
53
+ const baseRemote = remoteLocation.endsWith('/')
54
+ ? remoteLocation.slice(0, -1)
55
+ : remoteLocation;
56
+ return `${baseRemote}/remoteEntry.${remoteEntryExt}`;
57
+ }
58
+ return remoteLocation;
59
+ }
60
+ }
61
+ /**
62
+ * Processes remote URLs for runtime environments, resolving relative URLs against window.location.origin
63
+ */
64
+ function processRuntimeRemoteUrl(remoteUrl, remoteEntryExt) {
65
+ if (isAbsoluteUrl(remoteUrl)) {
66
+ return processRemoteLocation(remoteUrl, remoteEntryExt);
67
+ }
68
+ else {
69
+ // For runtime relative URLs, resolve against current origin
70
+ const baseUrl = typeof globalThis !== 'undefined' &&
71
+ typeof globalThis.window !== 'undefined' &&
72
+ globalThis.window.location
73
+ ? globalThis.window.location.origin
74
+ : 'http://localhost';
75
+ const absoluteUrl = new URL(remoteUrl, baseUrl).href;
76
+ return processRemoteLocation(absoluteUrl, remoteEntryExt);
77
+ }
78
+ }