@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 +34 -15
- package/package.json +6 -6
- package/src/executors/utils/build-static-remotes.js +5 -0
- package/src/plugins/nx-module-federation-plugin/angular/nx-module-federation-dev-server-plugin.js +3 -1
- package/src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-dev-server-plugin.js +3 -1
- package/src/plugins/utils/build-static-remotes.js +4 -0
- package/src/plugins/utils/get-dynamic-manifest-file.js +3 -2
- package/src/utils/dependencies.js +3 -2
- package/src/utils/remotes.js +11 -21
- package/src/utils/url-helpers.d.ts +13 -0
- package/src/utils/url-helpers.js +70 -0
- package/src/with-module-federation/angular/with-module-federation.js +1 -1
- package/src/with-module-federation/rspack/with-module-federation.js +1 -1
- package/src/with-module-federation/webpack/with-module-federation.js +1 -1
- package/url-helpers.d.ts +13 -0
- package/url-helpers.js +78 -0
package/migrations.json
CHANGED
|
@@ -23,21 +23,40 @@
|
|
|
23
23
|
},
|
|
24
24
|
"20.5.0": {
|
|
25
25
|
"version": "20.5.0-beta.5",
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
|
|
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.
|
|
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.
|
|
29
|
-
"@nx/js": "21.2.
|
|
30
|
-
"@nx/web": "21.2.
|
|
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.
|
|
34
|
+
"@module-federation/enhanced": "^0.15.0",
|
|
35
35
|
"@module-federation/node": "^2.6.26",
|
|
36
|
-
"@module-federation/sdk": "^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`);
|
package/src/plugins/nx-module-federation-plugin/angular/nx-module-federation-dev-server-plugin.js
CHANGED
|
@@ -48,7 +48,9 @@ class NxModuleFederationDevServerPlugin {
|
|
|
48
48
|
(0, utils_1.getDynamicMfManifestFile)(project, devkit_1.workspaceRoot);
|
|
49
49
|
}
|
|
50
50
|
else {
|
|
51
|
-
const userPathToManifestFile =
|
|
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
|
}
|
package/src/plugins/nx-module-federation-plugin/rspack/nx-module-federation-dev-server-plugin.js
CHANGED
|
@@ -48,7 +48,9 @@ class NxModuleFederationDevServerPlugin {
|
|
|
48
48
|
(0, utils_1.getDynamicMfManifestFile)(project, devkit_1.workspaceRoot);
|
|
49
49
|
}
|
|
50
50
|
else {
|
|
51
|
-
const userPathToManifestFile =
|
|
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
|
|
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
|
|
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
|
|
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);
|
package/src/utils/remotes.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.mapRemotes = mapRemotes;
|
|
4
4
|
exports.mapRemotesForSSR = mapRemotesForSSR;
|
|
5
|
-
const
|
|
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
|
-
|
|
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
|
|
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
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
};
|
package/url-helpers.d.ts
ADDED
|
@@ -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
|
+
}
|