@bleedingdev/modern-js-server-core 3.2.0-ultramodern.9 → 3.2.0-ultramodern.91
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/dist/cjs/adapters/node/plugins/moduleFederationCss.js +172 -0
- package/dist/cjs/adapters/node/plugins/resource.js +6 -1
- package/dist/cjs/plugins/render/csrRscRender.js +2 -0
- package/dist/cjs/plugins/render/renderRscHandler.js +2 -0
- package/dist/cjs/plugins/render/ssrRender.js +2 -0
- package/dist/esm/adapters/node/plugins/moduleFederationCss.mjs +125 -0
- package/dist/esm/adapters/node/plugins/resource.mjs +6 -1
- package/dist/esm/plugins/render/csrRscRender.mjs +2 -0
- package/dist/esm/plugins/render/renderRscHandler.mjs +2 -0
- package/dist/esm/plugins/render/ssrRender.mjs +2 -0
- package/dist/esm-node/adapters/node/plugins/moduleFederationCss.mjs +126 -0
- package/dist/esm-node/adapters/node/plugins/resource.mjs +6 -1
- package/dist/esm-node/plugins/render/csrRscRender.mjs +2 -0
- package/dist/esm-node/plugins/render/renderRscHandler.mjs +2 -0
- package/dist/esm-node/plugins/render/ssrRender.mjs +2 -0
- package/dist/types/adapters/node/plugins/moduleFederationCss.d.ts +33 -0
- package/dist/types/types/requestHandler.d.ts +1 -0
- package/dist/types/types/server.d.ts +1 -0
- package/package.json +11 -11
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.n = (module)=>{
|
|
5
|
+
var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
|
|
6
|
+
__webpack_require__.d(getter, {
|
|
7
|
+
a: getter
|
|
8
|
+
});
|
|
9
|
+
return getter;
|
|
10
|
+
};
|
|
11
|
+
})();
|
|
12
|
+
(()=>{
|
|
13
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
14
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: definition[key]
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
})();
|
|
20
|
+
(()=>{
|
|
21
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
22
|
+
})();
|
|
23
|
+
(()=>{
|
|
24
|
+
__webpack_require__.r = (exports1)=>{
|
|
25
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
26
|
+
value: 'Module'
|
|
27
|
+
});
|
|
28
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
29
|
+
value: true
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
})();
|
|
33
|
+
var __webpack_exports__ = {};
|
|
34
|
+
__webpack_require__.r(__webpack_exports__);
|
|
35
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
36
|
+
collectDirectRemoteModuleFederationCss: ()=>collectDirectRemoteModuleFederationCss,
|
|
37
|
+
collectModuleFederationManifestCss: ()=>collectModuleFederationManifestCss
|
|
38
|
+
});
|
|
39
|
+
const fileReader_namespaceObject = require("@modern-js/runtime-utils/fileReader");
|
|
40
|
+
const utils_namespaceObject = require("@modern-js/utils");
|
|
41
|
+
const external_path_namespaceObject = require("path");
|
|
42
|
+
var external_path_default = /*#__PURE__*/ __webpack_require__.n(external_path_namespaceObject);
|
|
43
|
+
const MODULE_FEDERATION_MANIFEST_FILE = 'mf-manifest.json';
|
|
44
|
+
const DEFAULT_REMOTE_MANIFEST_TIMEOUT = 1500;
|
|
45
|
+
const warn = (monitors, message, ...args)=>{
|
|
46
|
+
if (monitors) return void monitors.warn(message, ...args);
|
|
47
|
+
console.warn(message, ...args);
|
|
48
|
+
};
|
|
49
|
+
const ensureTrailingSlash = (value)=>value.endsWith('/') ? value : `${value}/`;
|
|
50
|
+
const tryResolveUrl = (value, base)=>{
|
|
51
|
+
try {
|
|
52
|
+
return new URL(value, base).toString();
|
|
53
|
+
} catch {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const normalizeRemoteEntry = (entry)=>{
|
|
58
|
+
const value = entry.trim();
|
|
59
|
+
if (!value) return;
|
|
60
|
+
const atIndex = value.lastIndexOf('@');
|
|
61
|
+
return atIndex >= 0 ? value.slice(atIndex + 1) : value;
|
|
62
|
+
};
|
|
63
|
+
const getCssAssets = (assets)=>[
|
|
64
|
+
...assets?.css?.sync || [],
|
|
65
|
+
...assets?.css?.async || []
|
|
66
|
+
];
|
|
67
|
+
const getManifestFallbackBase = (manifestUrl)=>{
|
|
68
|
+
try {
|
|
69
|
+
return new URL('.', manifestUrl).toString();
|
|
70
|
+
} catch {
|
|
71
|
+
return ensureTrailingSlash(manifestUrl);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const getManifestPublicPathBase = (publicPath, manifestUrl)=>{
|
|
75
|
+
if (!publicPath || 'auto' === publicPath) return getManifestFallbackBase(manifestUrl);
|
|
76
|
+
const base = tryResolveUrl(ensureTrailingSlash(publicPath), manifestUrl);
|
|
77
|
+
return base || getManifestFallbackBase(manifestUrl);
|
|
78
|
+
};
|
|
79
|
+
const appendResolvedCssAssets = (result, seen, assets, base)=>{
|
|
80
|
+
for (const asset of assets){
|
|
81
|
+
if (!asset) continue;
|
|
82
|
+
const resolved = tryResolveUrl(asset, base);
|
|
83
|
+
if (resolved && !seen.has(resolved)) {
|
|
84
|
+
seen.add(resolved);
|
|
85
|
+
result.push(resolved);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const collectModuleFederationManifestCss = (manifest, manifestUrl)=>{
|
|
90
|
+
const base = getManifestPublicPathBase(manifest.metaData?.publicPath, manifestUrl);
|
|
91
|
+
const result = [];
|
|
92
|
+
const seen = new Set();
|
|
93
|
+
for (const item of manifest.shared || [])appendResolvedCssAssets(result, seen, getCssAssets(item.assets), base);
|
|
94
|
+
for (const item of manifest.exposes || [])appendResolvedCssAssets(result, seen, getCssAssets(item.assets), base);
|
|
95
|
+
return result;
|
|
96
|
+
};
|
|
97
|
+
const fetchJsonWithTimeout = async (url, fetcher, timeout)=>{
|
|
98
|
+
const controller = new AbortController();
|
|
99
|
+
let timeoutId;
|
|
100
|
+
try {
|
|
101
|
+
const response = await Promise.race([
|
|
102
|
+
fetcher(url, {
|
|
103
|
+
signal: controller.signal
|
|
104
|
+
}),
|
|
105
|
+
new Promise((_, reject)=>{
|
|
106
|
+
timeoutId = setTimeout(()=>{
|
|
107
|
+
controller.abort();
|
|
108
|
+
reject(new Error(`Request timed out after ${timeout}ms`));
|
|
109
|
+
}, timeout);
|
|
110
|
+
})
|
|
111
|
+
]);
|
|
112
|
+
if (!response.ok) throw new Error(`Unexpected status ${response.status}`);
|
|
113
|
+
return await response.json();
|
|
114
|
+
} finally{
|
|
115
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
const getHostManifest = async (pwd, monitors)=>{
|
|
119
|
+
const manifestPath = external_path_default().join(pwd, MODULE_FEDERATION_MANIFEST_FILE);
|
|
120
|
+
if (!await utils_namespaceObject.fs.pathExists(manifestPath)) return;
|
|
121
|
+
const manifestBuffer = await fileReader_namespaceObject.fileReader.readFileFromSystem(manifestPath, 'buffer');
|
|
122
|
+
if (null === manifestBuffer) return;
|
|
123
|
+
try {
|
|
124
|
+
return JSON.parse(manifestBuffer.toString('utf-8'));
|
|
125
|
+
} catch (error) {
|
|
126
|
+
warn(monitors, 'Parse module federation manifest failed, error = %s', error instanceof Error ? error.message : error);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const collectDirectRemoteModuleFederationCss = async (pwd, options = {})=>{
|
|
131
|
+
const hostManifest = await getHostManifest(pwd, options.monitors);
|
|
132
|
+
if (!hostManifest) return [];
|
|
133
|
+
const fetcher = options.fetcher || globalThis.fetch?.bind(globalThis);
|
|
134
|
+
if (!fetcher) {
|
|
135
|
+
warn(options.monitors, 'Skip module federation remote CSS collection because fetch is unavailable.');
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
const timeout = options.timeout ?? DEFAULT_REMOTE_MANIFEST_TIMEOUT;
|
|
139
|
+
const cssAssets = [];
|
|
140
|
+
const seen = new Set();
|
|
141
|
+
for (const remote of hostManifest.remotes || []){
|
|
142
|
+
if (!remote.entry) continue;
|
|
143
|
+
const remoteEntry = normalizeRemoteEntry(remote.entry);
|
|
144
|
+
if (!remoteEntry) continue;
|
|
145
|
+
let remoteManifestUrl;
|
|
146
|
+
try {
|
|
147
|
+
remoteManifestUrl = new URL(remoteEntry).toString();
|
|
148
|
+
} catch {
|
|
149
|
+
warn(options.monitors, 'Skip module federation remote CSS collection for non-absolute manifest URL %s', remoteEntry);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const remoteManifest = await fetchJsonWithTimeout(remoteManifestUrl, fetcher, timeout);
|
|
154
|
+
for (const asset of collectModuleFederationManifestCss(remoteManifest, remoteManifestUrl))if (!seen.has(asset)) {
|
|
155
|
+
seen.add(asset);
|
|
156
|
+
cssAssets.push(asset);
|
|
157
|
+
}
|
|
158
|
+
} catch (error) {
|
|
159
|
+
warn(options.monitors, 'Load module federation remote manifest %s failed, error = %s', remoteManifestUrl, error instanceof Error ? error.message : error);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return cssAssets;
|
|
163
|
+
};
|
|
164
|
+
exports.collectDirectRemoteModuleFederationCss = __webpack_exports__.collectDirectRemoteModuleFederationCss;
|
|
165
|
+
exports.collectModuleFederationManifestCss = __webpack_exports__.collectModuleFederationManifestCss;
|
|
166
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
167
|
+
"collectDirectRemoteModuleFederationCss",
|
|
168
|
+
"collectModuleFederationManifestCss"
|
|
169
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
170
|
+
Object.defineProperty(exports, '__esModule', {
|
|
171
|
+
value: true
|
|
172
|
+
});
|
|
@@ -48,6 +48,7 @@ const utils_namespaceObject = require("@modern-js/utils");
|
|
|
48
48
|
const external_path_namespaceObject = require("path");
|
|
49
49
|
var external_path_default = /*#__PURE__*/ __webpack_require__.n(external_path_namespaceObject);
|
|
50
50
|
const index_js_namespaceObject = require("../../../utils/index.js");
|
|
51
|
+
const external_moduleFederationCss_js_namespaceObject = require("./moduleFederationCss.js");
|
|
51
52
|
async function getHtmlTemplates(pwd, routes) {
|
|
52
53
|
const htmlRoutes = routes.filter((route)=>route.entryName);
|
|
53
54
|
const htmls = await Promise.all(htmlRoutes.map(async (route)=>{
|
|
@@ -102,12 +103,16 @@ async function getServerManifest(pwd, routes, monitors) {
|
|
|
102
103
|
const routeManifest = await (0, utils_namespaceObject.compatibleRequire)(routesManifestUri).catch((_)=>({}));
|
|
103
104
|
const nestedRoutesJsonPath = external_path_default().join(pwd, utils_namespaceObject.NESTED_ROUTE_SPEC_FILE);
|
|
104
105
|
const nestedRoutesJson = await (0, utils_namespaceObject.compatibleRequire)(nestedRoutesJsonPath).catch((_)=>({}));
|
|
106
|
+
const moduleFederationCssAssets = await (0, external_moduleFederationCss_js_namespaceObject.collectDirectRemoteModuleFederationCss)(pwd, {
|
|
107
|
+
monitors
|
|
108
|
+
});
|
|
105
109
|
return {
|
|
106
110
|
loaderBundles,
|
|
107
111
|
renderBundles,
|
|
108
112
|
loadableStats,
|
|
109
113
|
routeManifest,
|
|
110
|
-
nestedRoutesJson
|
|
114
|
+
nestedRoutesJson,
|
|
115
|
+
moduleFederationCssAssets
|
|
111
116
|
};
|
|
112
117
|
}
|
|
113
118
|
function injectServerManifest(pwd, routes, manifestPromise) {
|
|
@@ -33,12 +33,14 @@ const csrRscRender = async (req, options)=>{
|
|
|
33
33
|
const serverBundle = serverManifest?.renderBundles?.[routeInfo.entryName || constants_namespaceObject.MAIN_ENTRY_NAME];
|
|
34
34
|
const loadableStats = serverManifest.loadableStats || {};
|
|
35
35
|
const routeManifest = serverManifest.routeManifest || {};
|
|
36
|
+
const moduleFederationCssAssets = serverManifest.moduleFederationCssAssets || [];
|
|
36
37
|
const config = (0, external_utils_js_namespaceObject.createRequestHandlerConfig)(options.config);
|
|
37
38
|
const requestHandlerOptions = {
|
|
38
39
|
resource: {
|
|
39
40
|
route: routeInfo,
|
|
40
41
|
loadableStats,
|
|
41
42
|
routeManifest,
|
|
43
|
+
moduleFederationCssAssets,
|
|
42
44
|
entryName: routeInfo.entryName || constants_namespaceObject.MAIN_ENTRY_NAME
|
|
43
45
|
},
|
|
44
46
|
config,
|
|
@@ -33,12 +33,14 @@ const renderRscHandler = async (req, options)=>{
|
|
|
33
33
|
const serverBundle = serverManifest?.renderBundles?.[routeInfo.entryName || constants_namespaceObject.MAIN_ENTRY_NAME];
|
|
34
34
|
const loadableStats = serverManifest.loadableStats || {};
|
|
35
35
|
const routeManifest = serverManifest.routeManifest || {};
|
|
36
|
+
const moduleFederationCssAssets = serverManifest.moduleFederationCssAssets || [];
|
|
36
37
|
const config = (0, external_utils_js_namespaceObject.createRequestHandlerConfig)(options.config);
|
|
37
38
|
const requestHandlerOptions = {
|
|
38
39
|
resource: {
|
|
39
40
|
route: routeInfo,
|
|
40
41
|
loadableStats,
|
|
41
42
|
routeManifest,
|
|
43
|
+
moduleFederationCssAssets,
|
|
42
44
|
entryName: routeInfo.entryName || constants_namespaceObject.MAIN_ENTRY_NAME
|
|
43
45
|
},
|
|
44
46
|
config,
|
|
@@ -36,6 +36,7 @@ async function ssrRender(request, { routeInfo, html, config: userConfig, staticG
|
|
|
36
36
|
const { entryName } = routeInfo;
|
|
37
37
|
const loadableStats = serverManifest.loadableStats || {};
|
|
38
38
|
const routeManifest = serverManifest.routeManifest || {};
|
|
39
|
+
const moduleFederationCssAssets = serverManifest.moduleFederationCssAssets || [];
|
|
39
40
|
const headers = (0, index_js_namespaceObject.parseHeaders)(request);
|
|
40
41
|
if (nodeReq) {
|
|
41
42
|
for(const key in nodeReq.headers)if (!headers[key]) headers[key] = nodeReq.headers[key];
|
|
@@ -49,6 +50,7 @@ async function ssrRender(request, { routeInfo, html, config: userConfig, staticG
|
|
|
49
50
|
route: routeInfo,
|
|
50
51
|
loadableStats,
|
|
51
52
|
routeManifest,
|
|
53
|
+
moduleFederationCssAssets,
|
|
52
54
|
htmlTemplate: html,
|
|
53
55
|
entryName: entryName || constants_namespaceObject.MAIN_ENTRY_NAME
|
|
54
56
|
},
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { fileReader } from "@modern-js/runtime-utils/fileReader";
|
|
2
|
+
import { fs } from "@modern-js/utils";
|
|
3
|
+
import path from "path";
|
|
4
|
+
const MODULE_FEDERATION_MANIFEST_FILE = 'mf-manifest.json';
|
|
5
|
+
const DEFAULT_REMOTE_MANIFEST_TIMEOUT = 1500;
|
|
6
|
+
const warn = (monitors, message, ...args)=>{
|
|
7
|
+
if (monitors) return void monitors.warn(message, ...args);
|
|
8
|
+
console.warn(message, ...args);
|
|
9
|
+
};
|
|
10
|
+
const ensureTrailingSlash = (value)=>value.endsWith('/') ? value : `${value}/`;
|
|
11
|
+
const tryResolveUrl = (value, base)=>{
|
|
12
|
+
try {
|
|
13
|
+
return new URL(value, base).toString();
|
|
14
|
+
} catch {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const normalizeRemoteEntry = (entry)=>{
|
|
19
|
+
const value = entry.trim();
|
|
20
|
+
if (!value) return;
|
|
21
|
+
const atIndex = value.lastIndexOf('@');
|
|
22
|
+
return atIndex >= 0 ? value.slice(atIndex + 1) : value;
|
|
23
|
+
};
|
|
24
|
+
const getCssAssets = (assets)=>[
|
|
25
|
+
...assets?.css?.sync || [],
|
|
26
|
+
...assets?.css?.async || []
|
|
27
|
+
];
|
|
28
|
+
const getManifestFallbackBase = (manifestUrl)=>{
|
|
29
|
+
try {
|
|
30
|
+
return new URL('.', manifestUrl).toString();
|
|
31
|
+
} catch {
|
|
32
|
+
return ensureTrailingSlash(manifestUrl);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const getManifestPublicPathBase = (publicPath, manifestUrl)=>{
|
|
36
|
+
if (!publicPath || 'auto' === publicPath) return getManifestFallbackBase(manifestUrl);
|
|
37
|
+
const base = tryResolveUrl(ensureTrailingSlash(publicPath), manifestUrl);
|
|
38
|
+
return base || getManifestFallbackBase(manifestUrl);
|
|
39
|
+
};
|
|
40
|
+
const appendResolvedCssAssets = (result, seen, assets, base)=>{
|
|
41
|
+
for (const asset of assets){
|
|
42
|
+
if (!asset) continue;
|
|
43
|
+
const resolved = tryResolveUrl(asset, base);
|
|
44
|
+
if (resolved && !seen.has(resolved)) {
|
|
45
|
+
seen.add(resolved);
|
|
46
|
+
result.push(resolved);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const collectModuleFederationManifestCss = (manifest, manifestUrl)=>{
|
|
51
|
+
const base = getManifestPublicPathBase(manifest.metaData?.publicPath, manifestUrl);
|
|
52
|
+
const result = [];
|
|
53
|
+
const seen = new Set();
|
|
54
|
+
for (const item of manifest.shared || [])appendResolvedCssAssets(result, seen, getCssAssets(item.assets), base);
|
|
55
|
+
for (const item of manifest.exposes || [])appendResolvedCssAssets(result, seen, getCssAssets(item.assets), base);
|
|
56
|
+
return result;
|
|
57
|
+
};
|
|
58
|
+
const fetchJsonWithTimeout = async (url, fetcher, timeout)=>{
|
|
59
|
+
const controller = new AbortController();
|
|
60
|
+
let timeoutId;
|
|
61
|
+
try {
|
|
62
|
+
const response = await Promise.race([
|
|
63
|
+
fetcher(url, {
|
|
64
|
+
signal: controller.signal
|
|
65
|
+
}),
|
|
66
|
+
new Promise((_, reject)=>{
|
|
67
|
+
timeoutId = setTimeout(()=>{
|
|
68
|
+
controller.abort();
|
|
69
|
+
reject(new Error(`Request timed out after ${timeout}ms`));
|
|
70
|
+
}, timeout);
|
|
71
|
+
})
|
|
72
|
+
]);
|
|
73
|
+
if (!response.ok) throw new Error(`Unexpected status ${response.status}`);
|
|
74
|
+
return await response.json();
|
|
75
|
+
} finally{
|
|
76
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const getHostManifest = async (pwd, monitors)=>{
|
|
80
|
+
const manifestPath = path.join(pwd, MODULE_FEDERATION_MANIFEST_FILE);
|
|
81
|
+
if (!await fs.pathExists(manifestPath)) return;
|
|
82
|
+
const manifestBuffer = await fileReader.readFileFromSystem(manifestPath, 'buffer');
|
|
83
|
+
if (null === manifestBuffer) return;
|
|
84
|
+
try {
|
|
85
|
+
return JSON.parse(manifestBuffer.toString('utf-8'));
|
|
86
|
+
} catch (error) {
|
|
87
|
+
warn(monitors, 'Parse module federation manifest failed, error = %s', error instanceof Error ? error.message : error);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const collectDirectRemoteModuleFederationCss = async (pwd, options = {})=>{
|
|
92
|
+
const hostManifest = await getHostManifest(pwd, options.monitors);
|
|
93
|
+
if (!hostManifest) return [];
|
|
94
|
+
const fetcher = options.fetcher || globalThis.fetch?.bind(globalThis);
|
|
95
|
+
if (!fetcher) {
|
|
96
|
+
warn(options.monitors, 'Skip module federation remote CSS collection because fetch is unavailable.');
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
const timeout = options.timeout ?? DEFAULT_REMOTE_MANIFEST_TIMEOUT;
|
|
100
|
+
const cssAssets = [];
|
|
101
|
+
const seen = new Set();
|
|
102
|
+
for (const remote of hostManifest.remotes || []){
|
|
103
|
+
if (!remote.entry) continue;
|
|
104
|
+
const remoteEntry = normalizeRemoteEntry(remote.entry);
|
|
105
|
+
if (!remoteEntry) continue;
|
|
106
|
+
let remoteManifestUrl;
|
|
107
|
+
try {
|
|
108
|
+
remoteManifestUrl = new URL(remoteEntry).toString();
|
|
109
|
+
} catch {
|
|
110
|
+
warn(options.monitors, 'Skip module federation remote CSS collection for non-absolute manifest URL %s', remoteEntry);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const remoteManifest = await fetchJsonWithTimeout(remoteManifestUrl, fetcher, timeout);
|
|
115
|
+
for (const asset of collectModuleFederationManifestCss(remoteManifest, remoteManifestUrl))if (!seen.has(asset)) {
|
|
116
|
+
seen.add(asset);
|
|
117
|
+
cssAssets.push(asset);
|
|
118
|
+
}
|
|
119
|
+
} catch (error) {
|
|
120
|
+
warn(options.monitors, 'Load module federation remote manifest %s failed, error = %s', remoteManifestUrl, error instanceof Error ? error.message : error);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return cssAssets;
|
|
124
|
+
};
|
|
125
|
+
export { collectDirectRemoteModuleFederationCss, collectModuleFederationManifestCss };
|
|
@@ -2,6 +2,7 @@ import { fileReader } from "@modern-js/runtime-utils/fileReader";
|
|
|
2
2
|
import { LOADABLE_STATS_FILE, MAIN_ENTRY_NAME, NESTED_ROUTE_SPEC_FILE, ROUTE_MANIFEST_FILE, SERVER_BUNDLE_DIRECTORY, compatibleRequire, fs, isProd } from "@modern-js/utils";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { uniqueKeyByRoute } from "../../../utils/index.mjs";
|
|
5
|
+
import { collectDirectRemoteModuleFederationCss } from "./moduleFederationCss.mjs";
|
|
5
6
|
async function getHtmlTemplates(pwd, routes) {
|
|
6
7
|
const htmlRoutes = routes.filter((route)=>route.entryName);
|
|
7
8
|
const htmls = await Promise.all(htmlRoutes.map(async (route)=>{
|
|
@@ -56,12 +57,16 @@ async function getServerManifest(pwd, routes, monitors) {
|
|
|
56
57
|
const routeManifest = await compatibleRequire(routesManifestUri).catch((_)=>({}));
|
|
57
58
|
const nestedRoutesJsonPath = path.join(pwd, NESTED_ROUTE_SPEC_FILE);
|
|
58
59
|
const nestedRoutesJson = await compatibleRequire(nestedRoutesJsonPath).catch((_)=>({}));
|
|
60
|
+
const moduleFederationCssAssets = await collectDirectRemoteModuleFederationCss(pwd, {
|
|
61
|
+
monitors
|
|
62
|
+
});
|
|
59
63
|
return {
|
|
60
64
|
loaderBundles,
|
|
61
65
|
renderBundles,
|
|
62
66
|
loadableStats,
|
|
63
67
|
routeManifest,
|
|
64
|
-
nestedRoutesJson
|
|
68
|
+
nestedRoutesJson,
|
|
69
|
+
moduleFederationCssAssets
|
|
65
70
|
};
|
|
66
71
|
}
|
|
67
72
|
function injectServerManifest(pwd, routes, manifestPromise) {
|
|
@@ -5,12 +5,14 @@ const csrRscRender = async (req, options)=>{
|
|
|
5
5
|
const serverBundle = serverManifest?.renderBundles?.[routeInfo.entryName || MAIN_ENTRY_NAME];
|
|
6
6
|
const loadableStats = serverManifest.loadableStats || {};
|
|
7
7
|
const routeManifest = serverManifest.routeManifest || {};
|
|
8
|
+
const moduleFederationCssAssets = serverManifest.moduleFederationCssAssets || [];
|
|
8
9
|
const config = createRequestHandlerConfig(options.config);
|
|
9
10
|
const requestHandlerOptions = {
|
|
10
11
|
resource: {
|
|
11
12
|
route: routeInfo,
|
|
12
13
|
loadableStats,
|
|
13
14
|
routeManifest,
|
|
15
|
+
moduleFederationCssAssets,
|
|
14
16
|
entryName: routeInfo.entryName || MAIN_ENTRY_NAME
|
|
15
17
|
},
|
|
16
18
|
config,
|
|
@@ -5,12 +5,14 @@ const renderRscHandler = async (req, options)=>{
|
|
|
5
5
|
const serverBundle = serverManifest?.renderBundles?.[routeInfo.entryName || MAIN_ENTRY_NAME];
|
|
6
6
|
const loadableStats = serverManifest.loadableStats || {};
|
|
7
7
|
const routeManifest = serverManifest.routeManifest || {};
|
|
8
|
+
const moduleFederationCssAssets = serverManifest.moduleFederationCssAssets || [];
|
|
8
9
|
const config = createRequestHandlerConfig(options.config);
|
|
9
10
|
const requestHandlerOptions = {
|
|
10
11
|
resource: {
|
|
11
12
|
route: routeInfo,
|
|
12
13
|
loadableStats,
|
|
13
14
|
routeManifest,
|
|
15
|
+
moduleFederationCssAssets,
|
|
14
16
|
entryName: routeInfo.entryName || MAIN_ENTRY_NAME
|
|
15
17
|
},
|
|
16
18
|
config,
|
|
@@ -8,6 +8,7 @@ async function ssrRender(request, { routeInfo, html, config: userConfig, staticG
|
|
|
8
8
|
const { entryName } = routeInfo;
|
|
9
9
|
const loadableStats = serverManifest.loadableStats || {};
|
|
10
10
|
const routeManifest = serverManifest.routeManifest || {};
|
|
11
|
+
const moduleFederationCssAssets = serverManifest.moduleFederationCssAssets || [];
|
|
11
12
|
const headers = parseHeaders(request);
|
|
12
13
|
if (nodeReq) {
|
|
13
14
|
for(const key in nodeReq.headers)if (!headers[key]) headers[key] = nodeReq.headers[key];
|
|
@@ -21,6 +22,7 @@ async function ssrRender(request, { routeInfo, html, config: userConfig, staticG
|
|
|
21
22
|
route: routeInfo,
|
|
22
23
|
loadableStats,
|
|
23
24
|
routeManifest,
|
|
25
|
+
moduleFederationCssAssets,
|
|
24
26
|
htmlTemplate: html,
|
|
25
27
|
entryName: entryName || MAIN_ENTRY_NAME
|
|
26
28
|
},
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { fileReader } from "@modern-js/runtime-utils/fileReader";
|
|
3
|
+
import { fs } from "@modern-js/utils";
|
|
4
|
+
import path from "path";
|
|
5
|
+
const MODULE_FEDERATION_MANIFEST_FILE = 'mf-manifest.json';
|
|
6
|
+
const DEFAULT_REMOTE_MANIFEST_TIMEOUT = 1500;
|
|
7
|
+
const warn = (monitors, message, ...args)=>{
|
|
8
|
+
if (monitors) return void monitors.warn(message, ...args);
|
|
9
|
+
console.warn(message, ...args);
|
|
10
|
+
};
|
|
11
|
+
const ensureTrailingSlash = (value)=>value.endsWith('/') ? value : `${value}/`;
|
|
12
|
+
const tryResolveUrl = (value, base)=>{
|
|
13
|
+
try {
|
|
14
|
+
return new URL(value, base).toString();
|
|
15
|
+
} catch {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const normalizeRemoteEntry = (entry)=>{
|
|
20
|
+
const value = entry.trim();
|
|
21
|
+
if (!value) return;
|
|
22
|
+
const atIndex = value.lastIndexOf('@');
|
|
23
|
+
return atIndex >= 0 ? value.slice(atIndex + 1) : value;
|
|
24
|
+
};
|
|
25
|
+
const getCssAssets = (assets)=>[
|
|
26
|
+
...assets?.css?.sync || [],
|
|
27
|
+
...assets?.css?.async || []
|
|
28
|
+
];
|
|
29
|
+
const getManifestFallbackBase = (manifestUrl)=>{
|
|
30
|
+
try {
|
|
31
|
+
return new URL('.', manifestUrl).toString();
|
|
32
|
+
} catch {
|
|
33
|
+
return ensureTrailingSlash(manifestUrl);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const getManifestPublicPathBase = (publicPath, manifestUrl)=>{
|
|
37
|
+
if (!publicPath || 'auto' === publicPath) return getManifestFallbackBase(manifestUrl);
|
|
38
|
+
const base = tryResolveUrl(ensureTrailingSlash(publicPath), manifestUrl);
|
|
39
|
+
return base || getManifestFallbackBase(manifestUrl);
|
|
40
|
+
};
|
|
41
|
+
const appendResolvedCssAssets = (result, seen, assets, base)=>{
|
|
42
|
+
for (const asset of assets){
|
|
43
|
+
if (!asset) continue;
|
|
44
|
+
const resolved = tryResolveUrl(asset, base);
|
|
45
|
+
if (resolved && !seen.has(resolved)) {
|
|
46
|
+
seen.add(resolved);
|
|
47
|
+
result.push(resolved);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const collectModuleFederationManifestCss = (manifest, manifestUrl)=>{
|
|
52
|
+
const base = getManifestPublicPathBase(manifest.metaData?.publicPath, manifestUrl);
|
|
53
|
+
const result = [];
|
|
54
|
+
const seen = new Set();
|
|
55
|
+
for (const item of manifest.shared || [])appendResolvedCssAssets(result, seen, getCssAssets(item.assets), base);
|
|
56
|
+
for (const item of manifest.exposes || [])appendResolvedCssAssets(result, seen, getCssAssets(item.assets), base);
|
|
57
|
+
return result;
|
|
58
|
+
};
|
|
59
|
+
const fetchJsonWithTimeout = async (url, fetcher, timeout)=>{
|
|
60
|
+
const controller = new AbortController();
|
|
61
|
+
let timeoutId;
|
|
62
|
+
try {
|
|
63
|
+
const response = await Promise.race([
|
|
64
|
+
fetcher(url, {
|
|
65
|
+
signal: controller.signal
|
|
66
|
+
}),
|
|
67
|
+
new Promise((_, reject)=>{
|
|
68
|
+
timeoutId = setTimeout(()=>{
|
|
69
|
+
controller.abort();
|
|
70
|
+
reject(new Error(`Request timed out after ${timeout}ms`));
|
|
71
|
+
}, timeout);
|
|
72
|
+
})
|
|
73
|
+
]);
|
|
74
|
+
if (!response.ok) throw new Error(`Unexpected status ${response.status}`);
|
|
75
|
+
return await response.json();
|
|
76
|
+
} finally{
|
|
77
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const getHostManifest = async (pwd, monitors)=>{
|
|
81
|
+
const manifestPath = path.join(pwd, MODULE_FEDERATION_MANIFEST_FILE);
|
|
82
|
+
if (!await fs.pathExists(manifestPath)) return;
|
|
83
|
+
const manifestBuffer = await fileReader.readFileFromSystem(manifestPath, 'buffer');
|
|
84
|
+
if (null === manifestBuffer) return;
|
|
85
|
+
try {
|
|
86
|
+
return JSON.parse(manifestBuffer.toString('utf-8'));
|
|
87
|
+
} catch (error) {
|
|
88
|
+
warn(monitors, 'Parse module federation manifest failed, error = %s', error instanceof Error ? error.message : error);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const collectDirectRemoteModuleFederationCss = async (pwd, options = {})=>{
|
|
93
|
+
const hostManifest = await getHostManifest(pwd, options.monitors);
|
|
94
|
+
if (!hostManifest) return [];
|
|
95
|
+
const fetcher = options.fetcher || globalThis.fetch?.bind(globalThis);
|
|
96
|
+
if (!fetcher) {
|
|
97
|
+
warn(options.monitors, 'Skip module federation remote CSS collection because fetch is unavailable.');
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
const timeout = options.timeout ?? DEFAULT_REMOTE_MANIFEST_TIMEOUT;
|
|
101
|
+
const cssAssets = [];
|
|
102
|
+
const seen = new Set();
|
|
103
|
+
for (const remote of hostManifest.remotes || []){
|
|
104
|
+
if (!remote.entry) continue;
|
|
105
|
+
const remoteEntry = normalizeRemoteEntry(remote.entry);
|
|
106
|
+
if (!remoteEntry) continue;
|
|
107
|
+
let remoteManifestUrl;
|
|
108
|
+
try {
|
|
109
|
+
remoteManifestUrl = new URL(remoteEntry).toString();
|
|
110
|
+
} catch {
|
|
111
|
+
warn(options.monitors, 'Skip module federation remote CSS collection for non-absolute manifest URL %s', remoteEntry);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const remoteManifest = await fetchJsonWithTimeout(remoteManifestUrl, fetcher, timeout);
|
|
116
|
+
for (const asset of collectModuleFederationManifestCss(remoteManifest, remoteManifestUrl))if (!seen.has(asset)) {
|
|
117
|
+
seen.add(asset);
|
|
118
|
+
cssAssets.push(asset);
|
|
119
|
+
}
|
|
120
|
+
} catch (error) {
|
|
121
|
+
warn(options.monitors, 'Load module federation remote manifest %s failed, error = %s', remoteManifestUrl, error instanceof Error ? error.message : error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return cssAssets;
|
|
125
|
+
};
|
|
126
|
+
export { collectDirectRemoteModuleFederationCss, collectModuleFederationManifestCss };
|
|
@@ -3,6 +3,7 @@ import { fileReader } from "@modern-js/runtime-utils/fileReader";
|
|
|
3
3
|
import { LOADABLE_STATS_FILE, MAIN_ENTRY_NAME, NESTED_ROUTE_SPEC_FILE, ROUTE_MANIFEST_FILE, SERVER_BUNDLE_DIRECTORY, compatibleRequire, fs, isProd } from "@modern-js/utils";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import { uniqueKeyByRoute } from "../../../utils/index.mjs";
|
|
6
|
+
import { collectDirectRemoteModuleFederationCss } from "./moduleFederationCss.mjs";
|
|
6
7
|
async function getHtmlTemplates(pwd, routes) {
|
|
7
8
|
const htmlRoutes = routes.filter((route)=>route.entryName);
|
|
8
9
|
const htmls = await Promise.all(htmlRoutes.map(async (route)=>{
|
|
@@ -57,12 +58,16 @@ async function getServerManifest(pwd, routes, monitors) {
|
|
|
57
58
|
const routeManifest = await compatibleRequire(routesManifestUri).catch((_)=>({}));
|
|
58
59
|
const nestedRoutesJsonPath = path.join(pwd, NESTED_ROUTE_SPEC_FILE);
|
|
59
60
|
const nestedRoutesJson = await compatibleRequire(nestedRoutesJsonPath).catch((_)=>({}));
|
|
61
|
+
const moduleFederationCssAssets = await collectDirectRemoteModuleFederationCss(pwd, {
|
|
62
|
+
monitors
|
|
63
|
+
});
|
|
60
64
|
return {
|
|
61
65
|
loaderBundles,
|
|
62
66
|
renderBundles,
|
|
63
67
|
loadableStats,
|
|
64
68
|
routeManifest,
|
|
65
|
-
nestedRoutesJson
|
|
69
|
+
nestedRoutesJson,
|
|
70
|
+
moduleFederationCssAssets
|
|
66
71
|
};
|
|
67
72
|
}
|
|
68
73
|
function injectServerManifest(pwd, routes, manifestPromise) {
|
|
@@ -6,12 +6,14 @@ const csrRscRender = async (req, options)=>{
|
|
|
6
6
|
const serverBundle = serverManifest?.renderBundles?.[routeInfo.entryName || MAIN_ENTRY_NAME];
|
|
7
7
|
const loadableStats = serverManifest.loadableStats || {};
|
|
8
8
|
const routeManifest = serverManifest.routeManifest || {};
|
|
9
|
+
const moduleFederationCssAssets = serverManifest.moduleFederationCssAssets || [];
|
|
9
10
|
const config = createRequestHandlerConfig(options.config);
|
|
10
11
|
const requestHandlerOptions = {
|
|
11
12
|
resource: {
|
|
12
13
|
route: routeInfo,
|
|
13
14
|
loadableStats,
|
|
14
15
|
routeManifest,
|
|
16
|
+
moduleFederationCssAssets,
|
|
15
17
|
entryName: routeInfo.entryName || MAIN_ENTRY_NAME
|
|
16
18
|
},
|
|
17
19
|
config,
|
|
@@ -6,12 +6,14 @@ const renderRscHandler = async (req, options)=>{
|
|
|
6
6
|
const serverBundle = serverManifest?.renderBundles?.[routeInfo.entryName || MAIN_ENTRY_NAME];
|
|
7
7
|
const loadableStats = serverManifest.loadableStats || {};
|
|
8
8
|
const routeManifest = serverManifest.routeManifest || {};
|
|
9
|
+
const moduleFederationCssAssets = serverManifest.moduleFederationCssAssets || [];
|
|
9
10
|
const config = createRequestHandlerConfig(options.config);
|
|
10
11
|
const requestHandlerOptions = {
|
|
11
12
|
resource: {
|
|
12
13
|
route: routeInfo,
|
|
13
14
|
loadableStats,
|
|
14
15
|
routeManifest,
|
|
16
|
+
moduleFederationCssAssets,
|
|
15
17
|
entryName: routeInfo.entryName || MAIN_ENTRY_NAME
|
|
16
18
|
},
|
|
17
19
|
config,
|
|
@@ -9,6 +9,7 @@ async function ssrRender(request, { routeInfo, html, config: userConfig, staticG
|
|
|
9
9
|
const { entryName } = routeInfo;
|
|
10
10
|
const loadableStats = serverManifest.loadableStats || {};
|
|
11
11
|
const routeManifest = serverManifest.routeManifest || {};
|
|
12
|
+
const moduleFederationCssAssets = serverManifest.moduleFederationCssAssets || [];
|
|
12
13
|
const headers = parseHeaders(request);
|
|
13
14
|
if (nodeReq) {
|
|
14
15
|
for(const key in nodeReq.headers)if (!headers[key]) headers[key] = nodeReq.headers[key];
|
|
@@ -22,6 +23,7 @@ async function ssrRender(request, { routeInfo, html, config: userConfig, staticG
|
|
|
22
23
|
route: routeInfo,
|
|
23
24
|
loadableStats,
|
|
24
25
|
routeManifest,
|
|
26
|
+
moduleFederationCssAssets,
|
|
25
27
|
htmlTemplate: html,
|
|
26
28
|
entryName: entryName || MAIN_ENTRY_NAME
|
|
27
29
|
},
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Monitors } from '@modern-js/types';
|
|
2
|
+
type ModuleFederationAssets = {
|
|
3
|
+
css?: {
|
|
4
|
+
sync?: string[];
|
|
5
|
+
async?: string[];
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
export type ModuleFederationManifest = {
|
|
9
|
+
metaData?: {
|
|
10
|
+
publicPath?: string;
|
|
11
|
+
};
|
|
12
|
+
shared?: Array<{
|
|
13
|
+
assets?: ModuleFederationAssets;
|
|
14
|
+
}>;
|
|
15
|
+
remotes?: Array<{
|
|
16
|
+
entry?: string;
|
|
17
|
+
assets?: ModuleFederationAssets;
|
|
18
|
+
}>;
|
|
19
|
+
exposes?: Array<{
|
|
20
|
+
assets?: ModuleFederationAssets;
|
|
21
|
+
}>;
|
|
22
|
+
};
|
|
23
|
+
type FetchLike = (input: string, init?: {
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
}) => Promise<Response>;
|
|
26
|
+
export type CollectDirectRemoteModuleFederationCssOptions = {
|
|
27
|
+
fetcher?: FetchLike;
|
|
28
|
+
monitors?: Monitors;
|
|
29
|
+
timeout?: number;
|
|
30
|
+
};
|
|
31
|
+
export declare const collectModuleFederationManifestCss: (manifest: ModuleFederationManifest, manifestUrl: string) => string[];
|
|
32
|
+
export declare const collectDirectRemoteModuleFederationCss: (pwd: string, options?: CollectDirectRemoteModuleFederationCssOptions) => Promise<string[]>;
|
|
33
|
+
export {};
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"modern",
|
|
18
18
|
"modern.js"
|
|
19
19
|
],
|
|
20
|
-
"version": "3.2.0-ultramodern.
|
|
20
|
+
"version": "3.2.0-ultramodern.91",
|
|
21
21
|
"types": "./dist/types/index.d.ts",
|
|
22
22
|
"main": "./dist/cjs/index.js",
|
|
23
23
|
"exports": {
|
|
@@ -68,27 +68,27 @@
|
|
|
68
68
|
"node": ">=20"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"@swc/helpers": "^0.5.
|
|
71
|
+
"@swc/helpers": "^0.5.23",
|
|
72
72
|
"@web-std/fetch": "^4.2.1",
|
|
73
73
|
"@web-std/file": "^3.0.3",
|
|
74
74
|
"@web-std/stream": "^1.0.3",
|
|
75
75
|
"cloneable-readable": "^3.0.0",
|
|
76
76
|
"flatted": "^3.4.2",
|
|
77
|
-
"hono": "^4.12.
|
|
78
|
-
"ts-deepmerge": "
|
|
79
|
-
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.2.0-ultramodern.
|
|
80
|
-
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.
|
|
81
|
-
"@modern-js/
|
|
77
|
+
"hono": "^4.12.22",
|
|
78
|
+
"ts-deepmerge": "8.0.0",
|
|
79
|
+
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.2.0-ultramodern.91",
|
|
80
|
+
"@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.2.0-ultramodern.91",
|
|
81
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.91"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@rslib/core": "0.21.5",
|
|
85
85
|
"@types/cloneable-readable": "^2.0.3",
|
|
86
86
|
"@types/merge-deep": "^3.0.3",
|
|
87
|
-
"@types/node": "^25.
|
|
88
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
87
|
+
"@types/node": "^25.9.1",
|
|
88
|
+
"@typescript/native-preview": "7.0.0-dev.20260527.2",
|
|
89
89
|
"http-proxy-middleware": "^4.0.0",
|
|
90
|
-
"@
|
|
91
|
-
"@
|
|
90
|
+
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.2.0-ultramodern.91",
|
|
91
|
+
"@scripts/rstest-config": "2.66.0"
|
|
92
92
|
},
|
|
93
93
|
"sideEffects": false,
|
|
94
94
|
"publishConfig": {
|