@module-federation/vite 1.10.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.cjs +160 -15
- package/lib/index.esm.js +160 -15
- package/lib/index.modern.js +179 -14
- package/lib/index.umd.js +160 -15
- package/lib/plugins/pluginVarRemoteEntry.d.ts +3 -0
- package/lib/utils/bundleHelpers.d.ts +2 -0
- package/lib/utils/normalizeModuleFederationOptions.d.ts +5 -0
- package/package.json +1 -1
package/lib/index.cjs
CHANGED
|
@@ -150,15 +150,44 @@ var addEntry = function addEntry(_ref) {
|
|
|
150
150
|
}
|
|
151
151
|
},
|
|
152
152
|
generateBundle: function generateBundle(options, bundle) {
|
|
153
|
-
var _viteConfig$experimen, _viteConfig$experimen2;
|
|
154
153
|
if (!injectHtml()) return;
|
|
155
154
|
var file = this.getFileName(emitFileId);
|
|
156
|
-
|
|
157
|
-
var
|
|
155
|
+
// Helper to resolve path with proper renderBuiltUrl handling
|
|
156
|
+
var resolvePath = function resolvePath(htmlFileName) {
|
|
157
|
+
var _viteConfig$experimen;
|
|
158
|
+
if (!((_viteConfig$experimen = viteConfig.experimental) != null && _viteConfig$experimen.renderBuiltUrl)) {
|
|
159
|
+
return viteConfig.base + file;
|
|
160
|
+
}
|
|
161
|
+
var result = viteConfig.experimental.renderBuiltUrl(file, {
|
|
162
|
+
hostId: htmlFileName,
|
|
163
|
+
hostType: 'html',
|
|
164
|
+
type: 'asset',
|
|
165
|
+
ssr: false
|
|
166
|
+
});
|
|
167
|
+
// Handle return types
|
|
168
|
+
if (typeof result === 'string') {
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
if (result && typeof result === 'object') {
|
|
172
|
+
if ('runtime' in result) {
|
|
173
|
+
// Runtime code cannot be used in <script src="">
|
|
174
|
+
console.warn('[vite-plugin-federation] renderBuiltUrl returned runtime code for HTML injection. ' + 'Runtime code cannot be used in <script src="">. Falling back to base path.');
|
|
175
|
+
return viteConfig.base + file;
|
|
176
|
+
}
|
|
177
|
+
if (result.relative) {
|
|
178
|
+
return file;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Fallback for undefined or unexpected values
|
|
182
|
+
return viteConfig.base + file;
|
|
183
|
+
};
|
|
184
|
+
// Process each HTML file
|
|
158
185
|
for (var _fileName in bundle) {
|
|
159
186
|
if (_fileName.endsWith('.html')) {
|
|
160
187
|
var htmlAsset = bundle[_fileName];
|
|
161
188
|
if (htmlAsset.type === 'chunk') return;
|
|
189
|
+
var _path = resolvePath(_fileName);
|
|
190
|
+
var scriptContent = "\n <script type=\"module\" src=\"" + _path + "\"></script>\n ";
|
|
162
191
|
var htmlContent = htmlAsset.source.toString() || '';
|
|
163
192
|
htmlContent = htmlContent.replace('<head>', "<head>" + scriptContent);
|
|
164
193
|
htmlAsset.source = htmlContent;
|
|
@@ -878,7 +907,8 @@ function normalizeModuleFederationOptions(options) {
|
|
|
878
907
|
virtualModuleDir: options.virtualModuleDir || '__mf__virtual',
|
|
879
908
|
hostInitInjectLocation: options.hostInitInjectLocation || 'html',
|
|
880
909
|
bundleAllCSS: options.bundleAllCSS || false,
|
|
881
|
-
moduleParseTimeout: options.moduleParseTimeout || 10
|
|
910
|
+
moduleParseTimeout: options.moduleParseTimeout || 10,
|
|
911
|
+
varFilename: options.varFilename
|
|
882
912
|
};
|
|
883
913
|
}
|
|
884
914
|
|
|
@@ -1289,6 +1319,16 @@ function initVirtualModules() {
|
|
|
1289
1319
|
writeRuntimeInitStatus();
|
|
1290
1320
|
}
|
|
1291
1321
|
|
|
1322
|
+
function findRemoteEntryFile(filename, bundle) {
|
|
1323
|
+
for (var _i = 0, _Object$entries = Object.entries(bundle); _i < _Object$entries.length; _i++) {
|
|
1324
|
+
var _Object$entries$_i = _Object$entries[_i],
|
|
1325
|
+
fileData = _Object$entries$_i[1];
|
|
1326
|
+
if (filename.replace(/[\[\]]/g, '_').replace(/\.[^/.]+$/, '') === fileData.name || fileData.name === 'remoteEntry') {
|
|
1327
|
+
return fileData.fileName; // We can return early since we only need to find remoteEntry once
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1292
1332
|
var ASSET_TYPES = ['js', 'css'];
|
|
1293
1333
|
var LOAD_TIMINGS = ['sync', 'async'];
|
|
1294
1334
|
var JS_EXTENSIONS = ['.ts', '.tsx', '.jsx', '.mjs', '.cjs'];
|
|
@@ -1466,7 +1506,8 @@ var Manifest = function Manifest() {
|
|
|
1466
1506
|
var name = mfOptions.name,
|
|
1467
1507
|
filename = mfOptions.filename,
|
|
1468
1508
|
getPublicPath = mfOptions.getPublicPath,
|
|
1469
|
-
manifestOptions = mfOptions.manifest
|
|
1509
|
+
manifestOptions = mfOptions.manifest,
|
|
1510
|
+
varFilename = mfOptions.varFilename;
|
|
1470
1511
|
var mfManifestName = '';
|
|
1471
1512
|
if (manifestOptions === true) {
|
|
1472
1513
|
mfManifestName = 'mf-manifest.json';
|
|
@@ -1539,6 +1580,11 @@ var Manifest = function Manifest() {
|
|
|
1539
1580
|
path: '',
|
|
1540
1581
|
type: 'module'
|
|
1541
1582
|
},
|
|
1583
|
+
varRemoteEntry: varFilename ? {
|
|
1584
|
+
name: varFilename,
|
|
1585
|
+
path: '',
|
|
1586
|
+
type: 'var'
|
|
1587
|
+
} : undefined,
|
|
1542
1588
|
types: {
|
|
1543
1589
|
path: '',
|
|
1544
1590
|
name: ''
|
|
@@ -1588,15 +1634,10 @@ var Manifest = function Manifest() {
|
|
|
1588
1634
|
var _this = this;
|
|
1589
1635
|
if (!mfManifestName) return Promise.resolve();
|
|
1590
1636
|
var filesMap = {};
|
|
1637
|
+
var foundRemoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
|
|
1591
1638
|
// First pass: Find remoteEntry file
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
_ = _Object$entries$_i[0],
|
|
1595
|
-
fileData = _Object$entries$_i[1];
|
|
1596
|
-
if (mfOptions.filename.replace(/[\[\]]/g, '_').replace(/\.[^/.]+$/, '') === fileData.name || fileData.name === 'remoteEntry') {
|
|
1597
|
-
remoteEntryFile = fileData.fileName;
|
|
1598
|
-
break; // We can break early since we only need to find remoteEntry once
|
|
1599
|
-
}
|
|
1639
|
+
if (foundRemoteEntryFile) {
|
|
1640
|
+
remoteEntryFile = foundRemoteEntryFile;
|
|
1600
1641
|
}
|
|
1601
1642
|
// Second pass: Collect all CSS assets
|
|
1602
1643
|
var allCssAssets = mfOptions.bundleAllCSS ? collectCssAssets(bundle) : new Set();
|
|
@@ -1651,12 +1692,18 @@ var Manifest = function Manifest() {
|
|
|
1651
1692
|
*/
|
|
1652
1693
|
function generateMFManifest(preloadMap) {
|
|
1653
1694
|
var options = getNormalizeModuleFederationOptions();
|
|
1654
|
-
var name = options.name
|
|
1695
|
+
var name = options.name,
|
|
1696
|
+
varFilename = options.varFilename;
|
|
1655
1697
|
var remoteEntry = {
|
|
1656
1698
|
name: remoteEntryFile,
|
|
1657
1699
|
path: '',
|
|
1658
1700
|
type: 'module'
|
|
1659
1701
|
};
|
|
1702
|
+
var varRemoteEntry = varFilename ? {
|
|
1703
|
+
name: varFilename,
|
|
1704
|
+
path: '',
|
|
1705
|
+
type: 'module'
|
|
1706
|
+
} : undefined;
|
|
1660
1707
|
// Process remotes
|
|
1661
1708
|
var remotes = Array.from(Object.entries(getUsedRemotesMap())).flatMap(function (_ref2) {
|
|
1662
1709
|
var remoteKey = _ref2[0],
|
|
@@ -1726,6 +1773,7 @@ var Manifest = function Manifest() {
|
|
|
1726
1773
|
},
|
|
1727
1774
|
remoteEntry: remoteEntry,
|
|
1728
1775
|
ssrRemoteEntry: remoteEntry,
|
|
1776
|
+
varRemoteEntry: varRemoteEntry,
|
|
1729
1777
|
types: {
|
|
1730
1778
|
path: '',
|
|
1731
1779
|
name: ''
|
|
@@ -2015,6 +2063,103 @@ function proxySharedModule(options) {
|
|
|
2015
2063
|
}];
|
|
2016
2064
|
}
|
|
2017
2065
|
|
|
2066
|
+
var VarRemoteEntry = function VarRemoteEntry() {
|
|
2067
|
+
var mfOptions = getNormalizeModuleFederationOptions();
|
|
2068
|
+
var name = mfOptions.name,
|
|
2069
|
+
varFilename = mfOptions.varFilename,
|
|
2070
|
+
filename = mfOptions.filename;
|
|
2071
|
+
var viteConfig;
|
|
2072
|
+
return [{
|
|
2073
|
+
name: 'module-federation-var-remote-entry',
|
|
2074
|
+
apply: 'serve',
|
|
2075
|
+
/**
|
|
2076
|
+
* Stores resolved Vite config for later use
|
|
2077
|
+
*/
|
|
2078
|
+
/**
|
|
2079
|
+
* Finalizes configuration after all plugins are resolved
|
|
2080
|
+
* @param config - Fully resolved Vite config
|
|
2081
|
+
*/
|
|
2082
|
+
configResolved: function configResolved(config) {
|
|
2083
|
+
viteConfig = config;
|
|
2084
|
+
},
|
|
2085
|
+
/**
|
|
2086
|
+
* Configures dev server middleware to handle varRemoteEntry requests
|
|
2087
|
+
* @param server - Vite dev server instance
|
|
2088
|
+
*/
|
|
2089
|
+
configureServer: function configureServer(server) {
|
|
2090
|
+
server.middlewares.use(function (req, res, next) {
|
|
2091
|
+
var _req$url;
|
|
2092
|
+
if (!varFilename) {
|
|
2093
|
+
next();
|
|
2094
|
+
return;
|
|
2095
|
+
}
|
|
2096
|
+
if (((_req$url = req.url) == null ? void 0 : _req$url.replace(/\?.*/, '')) === (viteConfig.base + varFilename).replace(/^\/?/, '/')) {
|
|
2097
|
+
res.setHeader('Content-Type', 'text/javascript');
|
|
2098
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
2099
|
+
console.log({
|
|
2100
|
+
filename: filename
|
|
2101
|
+
});
|
|
2102
|
+
res.end(generateVarRemoteEntry(filename));
|
|
2103
|
+
} else {
|
|
2104
|
+
next();
|
|
2105
|
+
}
|
|
2106
|
+
});
|
|
2107
|
+
}
|
|
2108
|
+
}, {
|
|
2109
|
+
name: 'module-federation-var-remote-entry',
|
|
2110
|
+
enforce: 'post',
|
|
2111
|
+
/**
|
|
2112
|
+
* Initial plugin configuration
|
|
2113
|
+
* @param config - Vite config object
|
|
2114
|
+
* @param command - Current Vite command (serve/build)
|
|
2115
|
+
*/
|
|
2116
|
+
config: function config(_config, _ref) {
|
|
2117
|
+
if (!_config.build) _config.build = {};
|
|
2118
|
+
},
|
|
2119
|
+
/**
|
|
2120
|
+
* Generates the module federation "var" remote entry file
|
|
2121
|
+
* @param options - Rollup output options
|
|
2122
|
+
* @param bundle - Generated bundle assets
|
|
2123
|
+
*/
|
|
2124
|
+
generateBundle: function generateBundle(options, bundle) {
|
|
2125
|
+
try {
|
|
2126
|
+
var _this = this;
|
|
2127
|
+
if (!varFilename) return Promise.resolve();
|
|
2128
|
+
var isValidName = isValidVarName(name);
|
|
2129
|
+
if (!isValidName) {
|
|
2130
|
+
viteConfig.logger.warn("Provided remote name \"" + name + "\" is not valid for \"var\" remoteEntry type, thus it's placed in globalThis['" + name + "'].\nIt may cause problems, so you would better want to use valid var name (see https://www.w3schools.com/js/js_variables.asp).");
|
|
2131
|
+
}
|
|
2132
|
+
var remoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
|
|
2133
|
+
if (!remoteEntryFile) throw new Error("Couldn't find a remoteEntry chunk file for " + mfOptions.filename + ", can't generate varRemoteEntry file");
|
|
2134
|
+
_this.emitFile({
|
|
2135
|
+
type: 'asset',
|
|
2136
|
+
fileName: varFilename,
|
|
2137
|
+
source: generateVarRemoteEntry(remoteEntryFile)
|
|
2138
|
+
});
|
|
2139
|
+
return Promise.resolve();
|
|
2140
|
+
} catch (e) {
|
|
2141
|
+
return Promise.reject(e);
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
}];
|
|
2145
|
+
function isValidVarName(name) {
|
|
2146
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
|
|
2147
|
+
}
|
|
2148
|
+
/**
|
|
2149
|
+
* Generates the final "var" remote entry file
|
|
2150
|
+
* @param remoteEntryFile - Path to esm remote entry file
|
|
2151
|
+
* @returns Complete "var" remoteEntry.js file source
|
|
2152
|
+
*/
|
|
2153
|
+
function generateVarRemoteEntry(remoteEntryFile) {
|
|
2154
|
+
var options = getNormalizeModuleFederationOptions();
|
|
2155
|
+
var name = options.name,
|
|
2156
|
+
varFilename = options.varFilename;
|
|
2157
|
+
var isValidName = isValidVarName(name);
|
|
2158
|
+
// todo: implement publicPath/getPublicPath support
|
|
2159
|
+
return "\n " + (isValidName ? "var " + name + ";" : '') + "\n " + (isValidName ? name : "globalThis['" + name + "']") + " = (function () {\n function getScriptUrl() {\n const currentScript = document.currentScript;\n if (!currentScript) {\n console.error(\"[VarRemoteEntry] " + varFilename + " script should be called from sync <script> tag (document.currentScript is undefined)\")\n return '/';\n }\n return document.currentScript.src.replace(/\\/[^/]*$/, '/');\n }\n\n const entry = getScriptUrl() + '" + remoteEntryFile + "';\n\n return {\n get: (...args) => import(entry).then(m => m.get(...args)),\n init: (...args) => import(entry).then(m => m.init(...args)),\n };\n })();\n ";
|
|
2160
|
+
}
|
|
2161
|
+
};
|
|
2162
|
+
|
|
2018
2163
|
var aliasToArrayPlugin = {
|
|
2019
2164
|
name: 'alias-transform-plugin',
|
|
2020
2165
|
config: function config(_config, _ref) {
|
|
@@ -2109,7 +2254,7 @@ function federation(mfUserOptions) {
|
|
|
2109
2254
|
(_config$optimizeDeps3 = _config.optimizeDeps) == null || (_config$optimizeDeps3 = _config$optimizeDeps3.needsInterop) == null || _config$optimizeDeps3.push(virtualDir);
|
|
2110
2255
|
(_config$optimizeDeps4 = _config.optimizeDeps) == null || (_config$optimizeDeps4 = _config$optimizeDeps4.needsInterop) == null || _config$optimizeDeps4.push(getLocalSharedImportMapPath());
|
|
2111
2256
|
}
|
|
2112
|
-
}], Manifest());
|
|
2257
|
+
}], Manifest(), VarRemoteEntry());
|
|
2113
2258
|
}
|
|
2114
2259
|
|
|
2115
2260
|
exports.federation = federation;
|
package/lib/index.esm.js
CHANGED
|
@@ -126,15 +126,44 @@ var addEntry = function addEntry(_ref) {
|
|
|
126
126
|
}
|
|
127
127
|
},
|
|
128
128
|
generateBundle: function generateBundle(options, bundle) {
|
|
129
|
-
var _viteConfig$experimen, _viteConfig$experimen2;
|
|
130
129
|
if (!injectHtml()) return;
|
|
131
130
|
var file = this.getFileName(emitFileId);
|
|
132
|
-
|
|
133
|
-
var
|
|
131
|
+
// Helper to resolve path with proper renderBuiltUrl handling
|
|
132
|
+
var resolvePath = function resolvePath(htmlFileName) {
|
|
133
|
+
var _viteConfig$experimen;
|
|
134
|
+
if (!((_viteConfig$experimen = viteConfig.experimental) != null && _viteConfig$experimen.renderBuiltUrl)) {
|
|
135
|
+
return viteConfig.base + file;
|
|
136
|
+
}
|
|
137
|
+
var result = viteConfig.experimental.renderBuiltUrl(file, {
|
|
138
|
+
hostId: htmlFileName,
|
|
139
|
+
hostType: 'html',
|
|
140
|
+
type: 'asset',
|
|
141
|
+
ssr: false
|
|
142
|
+
});
|
|
143
|
+
// Handle return types
|
|
144
|
+
if (typeof result === 'string') {
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
if (result && typeof result === 'object') {
|
|
148
|
+
if ('runtime' in result) {
|
|
149
|
+
// Runtime code cannot be used in <script src="">
|
|
150
|
+
console.warn('[vite-plugin-federation] renderBuiltUrl returned runtime code for HTML injection. ' + 'Runtime code cannot be used in <script src="">. Falling back to base path.');
|
|
151
|
+
return viteConfig.base + file;
|
|
152
|
+
}
|
|
153
|
+
if (result.relative) {
|
|
154
|
+
return file;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Fallback for undefined or unexpected values
|
|
158
|
+
return viteConfig.base + file;
|
|
159
|
+
};
|
|
160
|
+
// Process each HTML file
|
|
134
161
|
for (var _fileName in bundle) {
|
|
135
162
|
if (_fileName.endsWith('.html')) {
|
|
136
163
|
var htmlAsset = bundle[_fileName];
|
|
137
164
|
if (htmlAsset.type === 'chunk') return;
|
|
165
|
+
var _path = resolvePath(_fileName);
|
|
166
|
+
var scriptContent = "\n <script type=\"module\" src=\"" + _path + "\"></script>\n ";
|
|
138
167
|
var htmlContent = htmlAsset.source.toString() || '';
|
|
139
168
|
htmlContent = htmlContent.replace('<head>', "<head>" + scriptContent);
|
|
140
169
|
htmlAsset.source = htmlContent;
|
|
@@ -854,7 +883,8 @@ function normalizeModuleFederationOptions(options) {
|
|
|
854
883
|
virtualModuleDir: options.virtualModuleDir || '__mf__virtual',
|
|
855
884
|
hostInitInjectLocation: options.hostInitInjectLocation || 'html',
|
|
856
885
|
bundleAllCSS: options.bundleAllCSS || false,
|
|
857
|
-
moduleParseTimeout: options.moduleParseTimeout || 10
|
|
886
|
+
moduleParseTimeout: options.moduleParseTimeout || 10,
|
|
887
|
+
varFilename: options.varFilename
|
|
858
888
|
};
|
|
859
889
|
}
|
|
860
890
|
|
|
@@ -1265,6 +1295,16 @@ function initVirtualModules() {
|
|
|
1265
1295
|
writeRuntimeInitStatus();
|
|
1266
1296
|
}
|
|
1267
1297
|
|
|
1298
|
+
function findRemoteEntryFile(filename, bundle) {
|
|
1299
|
+
for (var _i = 0, _Object$entries = Object.entries(bundle); _i < _Object$entries.length; _i++) {
|
|
1300
|
+
var _Object$entries$_i = _Object$entries[_i],
|
|
1301
|
+
fileData = _Object$entries$_i[1];
|
|
1302
|
+
if (filename.replace(/[\[\]]/g, '_').replace(/\.[^/.]+$/, '') === fileData.name || fileData.name === 'remoteEntry') {
|
|
1303
|
+
return fileData.fileName; // We can return early since we only need to find remoteEntry once
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1268
1308
|
var ASSET_TYPES = ['js', 'css'];
|
|
1269
1309
|
var LOAD_TIMINGS = ['sync', 'async'];
|
|
1270
1310
|
var JS_EXTENSIONS = ['.ts', '.tsx', '.jsx', '.mjs', '.cjs'];
|
|
@@ -1442,7 +1482,8 @@ var Manifest = function Manifest() {
|
|
|
1442
1482
|
var name = mfOptions.name,
|
|
1443
1483
|
filename = mfOptions.filename,
|
|
1444
1484
|
getPublicPath = mfOptions.getPublicPath,
|
|
1445
|
-
manifestOptions = mfOptions.manifest
|
|
1485
|
+
manifestOptions = mfOptions.manifest,
|
|
1486
|
+
varFilename = mfOptions.varFilename;
|
|
1446
1487
|
var mfManifestName = '';
|
|
1447
1488
|
if (manifestOptions === true) {
|
|
1448
1489
|
mfManifestName = 'mf-manifest.json';
|
|
@@ -1515,6 +1556,11 @@ var Manifest = function Manifest() {
|
|
|
1515
1556
|
path: '',
|
|
1516
1557
|
type: 'module'
|
|
1517
1558
|
},
|
|
1559
|
+
varRemoteEntry: varFilename ? {
|
|
1560
|
+
name: varFilename,
|
|
1561
|
+
path: '',
|
|
1562
|
+
type: 'var'
|
|
1563
|
+
} : undefined,
|
|
1518
1564
|
types: {
|
|
1519
1565
|
path: '',
|
|
1520
1566
|
name: ''
|
|
@@ -1564,15 +1610,10 @@ var Manifest = function Manifest() {
|
|
|
1564
1610
|
var _this = this;
|
|
1565
1611
|
if (!mfManifestName) return Promise.resolve();
|
|
1566
1612
|
var filesMap = {};
|
|
1613
|
+
var foundRemoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
|
|
1567
1614
|
// First pass: Find remoteEntry file
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
_ = _Object$entries$_i[0],
|
|
1571
|
-
fileData = _Object$entries$_i[1];
|
|
1572
|
-
if (mfOptions.filename.replace(/[\[\]]/g, '_').replace(/\.[^/.]+$/, '') === fileData.name || fileData.name === 'remoteEntry') {
|
|
1573
|
-
remoteEntryFile = fileData.fileName;
|
|
1574
|
-
break; // We can break early since we only need to find remoteEntry once
|
|
1575
|
-
}
|
|
1615
|
+
if (foundRemoteEntryFile) {
|
|
1616
|
+
remoteEntryFile = foundRemoteEntryFile;
|
|
1576
1617
|
}
|
|
1577
1618
|
// Second pass: Collect all CSS assets
|
|
1578
1619
|
var allCssAssets = mfOptions.bundleAllCSS ? collectCssAssets(bundle) : new Set();
|
|
@@ -1627,12 +1668,18 @@ var Manifest = function Manifest() {
|
|
|
1627
1668
|
*/
|
|
1628
1669
|
function generateMFManifest(preloadMap) {
|
|
1629
1670
|
var options = getNormalizeModuleFederationOptions();
|
|
1630
|
-
var name = options.name
|
|
1671
|
+
var name = options.name,
|
|
1672
|
+
varFilename = options.varFilename;
|
|
1631
1673
|
var remoteEntry = {
|
|
1632
1674
|
name: remoteEntryFile,
|
|
1633
1675
|
path: '',
|
|
1634
1676
|
type: 'module'
|
|
1635
1677
|
};
|
|
1678
|
+
var varRemoteEntry = varFilename ? {
|
|
1679
|
+
name: varFilename,
|
|
1680
|
+
path: '',
|
|
1681
|
+
type: 'module'
|
|
1682
|
+
} : undefined;
|
|
1636
1683
|
// Process remotes
|
|
1637
1684
|
var remotes = Array.from(Object.entries(getUsedRemotesMap())).flatMap(function (_ref2) {
|
|
1638
1685
|
var remoteKey = _ref2[0],
|
|
@@ -1702,6 +1749,7 @@ var Manifest = function Manifest() {
|
|
|
1702
1749
|
},
|
|
1703
1750
|
remoteEntry: remoteEntry,
|
|
1704
1751
|
ssrRemoteEntry: remoteEntry,
|
|
1752
|
+
varRemoteEntry: varRemoteEntry,
|
|
1705
1753
|
types: {
|
|
1706
1754
|
path: '',
|
|
1707
1755
|
name: ''
|
|
@@ -1991,6 +2039,103 @@ function proxySharedModule(options) {
|
|
|
1991
2039
|
}];
|
|
1992
2040
|
}
|
|
1993
2041
|
|
|
2042
|
+
var VarRemoteEntry = function VarRemoteEntry() {
|
|
2043
|
+
var mfOptions = getNormalizeModuleFederationOptions();
|
|
2044
|
+
var name = mfOptions.name,
|
|
2045
|
+
varFilename = mfOptions.varFilename,
|
|
2046
|
+
filename = mfOptions.filename;
|
|
2047
|
+
var viteConfig;
|
|
2048
|
+
return [{
|
|
2049
|
+
name: 'module-federation-var-remote-entry',
|
|
2050
|
+
apply: 'serve',
|
|
2051
|
+
/**
|
|
2052
|
+
* Stores resolved Vite config for later use
|
|
2053
|
+
*/
|
|
2054
|
+
/**
|
|
2055
|
+
* Finalizes configuration after all plugins are resolved
|
|
2056
|
+
* @param config - Fully resolved Vite config
|
|
2057
|
+
*/
|
|
2058
|
+
configResolved: function configResolved(config) {
|
|
2059
|
+
viteConfig = config;
|
|
2060
|
+
},
|
|
2061
|
+
/**
|
|
2062
|
+
* Configures dev server middleware to handle varRemoteEntry requests
|
|
2063
|
+
* @param server - Vite dev server instance
|
|
2064
|
+
*/
|
|
2065
|
+
configureServer: function configureServer(server) {
|
|
2066
|
+
server.middlewares.use(function (req, res, next) {
|
|
2067
|
+
var _req$url;
|
|
2068
|
+
if (!varFilename) {
|
|
2069
|
+
next();
|
|
2070
|
+
return;
|
|
2071
|
+
}
|
|
2072
|
+
if (((_req$url = req.url) == null ? void 0 : _req$url.replace(/\?.*/, '')) === (viteConfig.base + varFilename).replace(/^\/?/, '/')) {
|
|
2073
|
+
res.setHeader('Content-Type', 'text/javascript');
|
|
2074
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
2075
|
+
console.log({
|
|
2076
|
+
filename: filename
|
|
2077
|
+
});
|
|
2078
|
+
res.end(generateVarRemoteEntry(filename));
|
|
2079
|
+
} else {
|
|
2080
|
+
next();
|
|
2081
|
+
}
|
|
2082
|
+
});
|
|
2083
|
+
}
|
|
2084
|
+
}, {
|
|
2085
|
+
name: 'module-federation-var-remote-entry',
|
|
2086
|
+
enforce: 'post',
|
|
2087
|
+
/**
|
|
2088
|
+
* Initial plugin configuration
|
|
2089
|
+
* @param config - Vite config object
|
|
2090
|
+
* @param command - Current Vite command (serve/build)
|
|
2091
|
+
*/
|
|
2092
|
+
config: function config(_config, _ref) {
|
|
2093
|
+
if (!_config.build) _config.build = {};
|
|
2094
|
+
},
|
|
2095
|
+
/**
|
|
2096
|
+
* Generates the module federation "var" remote entry file
|
|
2097
|
+
* @param options - Rollup output options
|
|
2098
|
+
* @param bundle - Generated bundle assets
|
|
2099
|
+
*/
|
|
2100
|
+
generateBundle: function generateBundle(options, bundle) {
|
|
2101
|
+
try {
|
|
2102
|
+
var _this = this;
|
|
2103
|
+
if (!varFilename) return Promise.resolve();
|
|
2104
|
+
var isValidName = isValidVarName(name);
|
|
2105
|
+
if (!isValidName) {
|
|
2106
|
+
viteConfig.logger.warn("Provided remote name \"" + name + "\" is not valid for \"var\" remoteEntry type, thus it's placed in globalThis['" + name + "'].\nIt may cause problems, so you would better want to use valid var name (see https://www.w3schools.com/js/js_variables.asp).");
|
|
2107
|
+
}
|
|
2108
|
+
var remoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
|
|
2109
|
+
if (!remoteEntryFile) throw new Error("Couldn't find a remoteEntry chunk file for " + mfOptions.filename + ", can't generate varRemoteEntry file");
|
|
2110
|
+
_this.emitFile({
|
|
2111
|
+
type: 'asset',
|
|
2112
|
+
fileName: varFilename,
|
|
2113
|
+
source: generateVarRemoteEntry(remoteEntryFile)
|
|
2114
|
+
});
|
|
2115
|
+
return Promise.resolve();
|
|
2116
|
+
} catch (e) {
|
|
2117
|
+
return Promise.reject(e);
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
}];
|
|
2121
|
+
function isValidVarName(name) {
|
|
2122
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
|
|
2123
|
+
}
|
|
2124
|
+
/**
|
|
2125
|
+
* Generates the final "var" remote entry file
|
|
2126
|
+
* @param remoteEntryFile - Path to esm remote entry file
|
|
2127
|
+
* @returns Complete "var" remoteEntry.js file source
|
|
2128
|
+
*/
|
|
2129
|
+
function generateVarRemoteEntry(remoteEntryFile) {
|
|
2130
|
+
var options = getNormalizeModuleFederationOptions();
|
|
2131
|
+
var name = options.name,
|
|
2132
|
+
varFilename = options.varFilename;
|
|
2133
|
+
var isValidName = isValidVarName(name);
|
|
2134
|
+
// todo: implement publicPath/getPublicPath support
|
|
2135
|
+
return "\n " + (isValidName ? "var " + name + ";" : '') + "\n " + (isValidName ? name : "globalThis['" + name + "']") + " = (function () {\n function getScriptUrl() {\n const currentScript = document.currentScript;\n if (!currentScript) {\n console.error(\"[VarRemoteEntry] " + varFilename + " script should be called from sync <script> tag (document.currentScript is undefined)\")\n return '/';\n }\n return document.currentScript.src.replace(/\\/[^/]*$/, '/');\n }\n\n const entry = getScriptUrl() + '" + remoteEntryFile + "';\n\n return {\n get: (...args) => import(entry).then(m => m.get(...args)),\n init: (...args) => import(entry).then(m => m.init(...args)),\n };\n })();\n ";
|
|
2136
|
+
}
|
|
2137
|
+
};
|
|
2138
|
+
|
|
1994
2139
|
var aliasToArrayPlugin = {
|
|
1995
2140
|
name: 'alias-transform-plugin',
|
|
1996
2141
|
config: function config(_config, _ref) {
|
|
@@ -2085,7 +2230,7 @@ function federation(mfUserOptions) {
|
|
|
2085
2230
|
(_config$optimizeDeps3 = _config.optimizeDeps) == null || (_config$optimizeDeps3 = _config$optimizeDeps3.needsInterop) == null || _config$optimizeDeps3.push(virtualDir);
|
|
2086
2231
|
(_config$optimizeDeps4 = _config.optimizeDeps) == null || (_config$optimizeDeps4 = _config$optimizeDeps4.needsInterop) == null || _config$optimizeDeps4.push(getLocalSharedImportMapPath());
|
|
2087
2232
|
}
|
|
2088
|
-
}], Manifest());
|
|
2233
|
+
}], Manifest(), VarRemoteEntry());
|
|
2089
2234
|
}
|
|
2090
2235
|
|
|
2091
2236
|
export { federation };
|
package/lib/index.modern.js
CHANGED
|
@@ -124,17 +124,46 @@ const addEntry = ({
|
|
|
124
124
|
}
|
|
125
125
|
},
|
|
126
126
|
generateBundle(options, bundle) {
|
|
127
|
-
var _viteConfig$experimen, _viteConfig$experimen2;
|
|
128
127
|
if (!injectHtml()) return;
|
|
129
128
|
const file = this.getFileName(emitFileId);
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
// Helper to resolve path with proper renderBuiltUrl handling
|
|
130
|
+
const resolvePath = htmlFileName => {
|
|
131
|
+
var _viteConfig$experimen;
|
|
132
|
+
if (!((_viteConfig$experimen = viteConfig.experimental) != null && _viteConfig$experimen.renderBuiltUrl)) {
|
|
133
|
+
return viteConfig.base + file;
|
|
134
|
+
}
|
|
135
|
+
const result = viteConfig.experimental.renderBuiltUrl(file, {
|
|
136
|
+
hostId: htmlFileName,
|
|
137
|
+
hostType: 'html',
|
|
138
|
+
type: 'asset',
|
|
139
|
+
ssr: false
|
|
140
|
+
});
|
|
141
|
+
// Handle return types
|
|
142
|
+
if (typeof result === 'string') {
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
if (result && typeof result === 'object') {
|
|
146
|
+
if ('runtime' in result) {
|
|
147
|
+
// Runtime code cannot be used in <script src="">
|
|
148
|
+
console.warn('[vite-plugin-federation] renderBuiltUrl returned runtime code for HTML injection. ' + 'Runtime code cannot be used in <script src="">. Falling back to base path.');
|
|
149
|
+
return viteConfig.base + file;
|
|
150
|
+
}
|
|
151
|
+
if (result.relative) {
|
|
152
|
+
return file;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Fallback for undefined or unexpected values
|
|
156
|
+
return viteConfig.base + file;
|
|
157
|
+
};
|
|
158
|
+
// Process each HTML file
|
|
134
159
|
for (const fileName in bundle) {
|
|
135
160
|
if (fileName.endsWith('.html')) {
|
|
136
161
|
let htmlAsset = bundle[fileName];
|
|
137
162
|
if (htmlAsset.type === 'chunk') return;
|
|
163
|
+
const path = resolvePath(fileName);
|
|
164
|
+
const scriptContent = `
|
|
165
|
+
<script type="module" src="${path}"></script>
|
|
166
|
+
`;
|
|
138
167
|
let htmlContent = htmlAsset.source.toString() || '';
|
|
139
168
|
htmlContent = htmlContent.replace('<head>', `<head>${scriptContent}`);
|
|
140
169
|
htmlAsset.source = htmlContent;
|
|
@@ -789,7 +818,8 @@ function normalizeModuleFederationOptions(options) {
|
|
|
789
818
|
virtualModuleDir: options.virtualModuleDir || '__mf__virtual',
|
|
790
819
|
hostInitInjectLocation: options.hostInitInjectLocation || 'html',
|
|
791
820
|
bundleAllCSS: options.bundleAllCSS || false,
|
|
792
|
-
moduleParseTimeout: options.moduleParseTimeout || 10
|
|
821
|
+
moduleParseTimeout: options.moduleParseTimeout || 10,
|
|
822
|
+
varFilename: options.varFilename
|
|
793
823
|
};
|
|
794
824
|
}
|
|
795
825
|
|
|
@@ -1335,6 +1365,14 @@ function initVirtualModules() {
|
|
|
1335
1365
|
writeRuntimeInitStatus();
|
|
1336
1366
|
}
|
|
1337
1367
|
|
|
1368
|
+
function findRemoteEntryFile(filename, bundle) {
|
|
1369
|
+
for (const [_, fileData] of Object.entries(bundle)) {
|
|
1370
|
+
if (filename.replace(/[\[\]]/g, '_').replace(/\.[^/.]+$/, '') === fileData.name || fileData.name === 'remoteEntry') {
|
|
1371
|
+
return fileData.fileName; // We can return early since we only need to find remoteEntry once
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1338
1376
|
const ASSET_TYPES = ['js', 'css'];
|
|
1339
1377
|
const LOAD_TIMINGS = ['sync', 'async'];
|
|
1340
1378
|
const JS_EXTENSIONS = ['.ts', '.tsx', '.jsx', '.mjs', '.cjs'];
|
|
@@ -1488,7 +1526,8 @@ const Manifest = () => {
|
|
|
1488
1526
|
name,
|
|
1489
1527
|
filename,
|
|
1490
1528
|
getPublicPath,
|
|
1491
|
-
manifest: manifestOptions
|
|
1529
|
+
manifest: manifestOptions,
|
|
1530
|
+
varFilename
|
|
1492
1531
|
} = mfOptions;
|
|
1493
1532
|
let mfManifestName = '';
|
|
1494
1533
|
if (manifestOptions === true) {
|
|
@@ -1562,6 +1601,11 @@ const Manifest = () => {
|
|
|
1562
1601
|
path: '',
|
|
1563
1602
|
type: 'module'
|
|
1564
1603
|
},
|
|
1604
|
+
varRemoteEntry: varFilename ? {
|
|
1605
|
+
name: varFilename,
|
|
1606
|
+
path: '',
|
|
1607
|
+
type: 'var'
|
|
1608
|
+
} : undefined,
|
|
1565
1609
|
types: {
|
|
1566
1610
|
path: '',
|
|
1567
1611
|
name: ''
|
|
@@ -1610,12 +1654,10 @@ const Manifest = () => {
|
|
|
1610
1654
|
async generateBundle(options, bundle) {
|
|
1611
1655
|
if (!mfManifestName) return;
|
|
1612
1656
|
let filesMap = {};
|
|
1657
|
+
const foundRemoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
|
|
1613
1658
|
// First pass: Find remoteEntry file
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
remoteEntryFile = fileData.fileName;
|
|
1617
|
-
break; // We can break early since we only need to find remoteEntry once
|
|
1618
|
-
}
|
|
1659
|
+
if (foundRemoteEntryFile) {
|
|
1660
|
+
remoteEntryFile = foundRemoteEntryFile;
|
|
1619
1661
|
}
|
|
1620
1662
|
// Second pass: Collect all CSS assets
|
|
1621
1663
|
const allCssAssets = mfOptions.bundleAllCSS ? collectCssAssets(bundle) : new Set();
|
|
@@ -1663,13 +1705,19 @@ const Manifest = () => {
|
|
|
1663
1705
|
function generateMFManifest(preloadMap) {
|
|
1664
1706
|
const options = getNormalizeModuleFederationOptions();
|
|
1665
1707
|
const {
|
|
1666
|
-
name
|
|
1708
|
+
name,
|
|
1709
|
+
varFilename
|
|
1667
1710
|
} = options;
|
|
1668
1711
|
const remoteEntry = {
|
|
1669
1712
|
name: remoteEntryFile,
|
|
1670
1713
|
path: '',
|
|
1671
1714
|
type: 'module'
|
|
1672
1715
|
};
|
|
1716
|
+
const varRemoteEntry = varFilename ? {
|
|
1717
|
+
name: varFilename,
|
|
1718
|
+
path: '',
|
|
1719
|
+
type: 'module'
|
|
1720
|
+
} : undefined;
|
|
1673
1721
|
// Process remotes
|
|
1674
1722
|
const remotes = Array.from(Object.entries(getUsedRemotesMap())).flatMap(([remoteKey, modules]) => Array.from(modules).map(moduleKey => ({
|
|
1675
1723
|
federationContainerName: options.remotes[remoteKey].entry,
|
|
@@ -1731,6 +1779,7 @@ const Manifest = () => {
|
|
|
1731
1779
|
},
|
|
1732
1780
|
remoteEntry,
|
|
1733
1781
|
ssrRemoteEntry: remoteEntry,
|
|
1782
|
+
varRemoteEntry,
|
|
1734
1783
|
types: {
|
|
1735
1784
|
path: '',
|
|
1736
1785
|
name: ''
|
|
@@ -2014,6 +2063,122 @@ function proxySharedModule(options) {
|
|
|
2014
2063
|
}];
|
|
2015
2064
|
}
|
|
2016
2065
|
|
|
2066
|
+
const VarRemoteEntry = () => {
|
|
2067
|
+
const mfOptions = getNormalizeModuleFederationOptions();
|
|
2068
|
+
const {
|
|
2069
|
+
name,
|
|
2070
|
+
varFilename,
|
|
2071
|
+
filename
|
|
2072
|
+
} = mfOptions;
|
|
2073
|
+
let viteConfig;
|
|
2074
|
+
return [{
|
|
2075
|
+
name: 'module-federation-var-remote-entry',
|
|
2076
|
+
apply: 'serve',
|
|
2077
|
+
/**
|
|
2078
|
+
* Stores resolved Vite config for later use
|
|
2079
|
+
*/
|
|
2080
|
+
/**
|
|
2081
|
+
* Finalizes configuration after all plugins are resolved
|
|
2082
|
+
* @param config - Fully resolved Vite config
|
|
2083
|
+
*/
|
|
2084
|
+
configResolved(config) {
|
|
2085
|
+
viteConfig = config;
|
|
2086
|
+
},
|
|
2087
|
+
/**
|
|
2088
|
+
* Configures dev server middleware to handle varRemoteEntry requests
|
|
2089
|
+
* @param server - Vite dev server instance
|
|
2090
|
+
*/
|
|
2091
|
+
configureServer(server) {
|
|
2092
|
+
server.middlewares.use((req, res, next) => {
|
|
2093
|
+
var _req$url;
|
|
2094
|
+
if (!varFilename) {
|
|
2095
|
+
next();
|
|
2096
|
+
return;
|
|
2097
|
+
}
|
|
2098
|
+
if (((_req$url = req.url) == null ? void 0 : _req$url.replace(/\?.*/, '')) === (viteConfig.base + varFilename).replace(/^\/?/, '/')) {
|
|
2099
|
+
res.setHeader('Content-Type', 'text/javascript');
|
|
2100
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
2101
|
+
console.log({
|
|
2102
|
+
filename
|
|
2103
|
+
});
|
|
2104
|
+
res.end(generateVarRemoteEntry(filename));
|
|
2105
|
+
} else {
|
|
2106
|
+
next();
|
|
2107
|
+
}
|
|
2108
|
+
});
|
|
2109
|
+
}
|
|
2110
|
+
}, {
|
|
2111
|
+
name: 'module-federation-var-remote-entry',
|
|
2112
|
+
enforce: 'post',
|
|
2113
|
+
/**
|
|
2114
|
+
* Initial plugin configuration
|
|
2115
|
+
* @param config - Vite config object
|
|
2116
|
+
* @param command - Current Vite command (serve/build)
|
|
2117
|
+
*/
|
|
2118
|
+
config(config, {
|
|
2119
|
+
command
|
|
2120
|
+
}) {
|
|
2121
|
+
if (!config.build) config.build = {};
|
|
2122
|
+
},
|
|
2123
|
+
/**
|
|
2124
|
+
* Generates the module federation "var" remote entry file
|
|
2125
|
+
* @param options - Rollup output options
|
|
2126
|
+
* @param bundle - Generated bundle assets
|
|
2127
|
+
*/
|
|
2128
|
+
async generateBundle(options, bundle) {
|
|
2129
|
+
if (!varFilename) return;
|
|
2130
|
+
const isValidName = isValidVarName(name);
|
|
2131
|
+
if (!isValidName) {
|
|
2132
|
+
viteConfig.logger.warn(`Provided remote name "${name}" is not valid for "var" remoteEntry type, thus it's placed in globalThis['${name}'].\nIt may cause problems, so you would better want to use valid var name (see https://www.w3schools.com/js/js_variables.asp).`);
|
|
2133
|
+
}
|
|
2134
|
+
const remoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
|
|
2135
|
+
if (!remoteEntryFile) throw new Error(`Couldn't find a remoteEntry chunk file for ${mfOptions.filename}, can't generate varRemoteEntry file`);
|
|
2136
|
+
this.emitFile({
|
|
2137
|
+
type: 'asset',
|
|
2138
|
+
fileName: varFilename,
|
|
2139
|
+
source: generateVarRemoteEntry(remoteEntryFile)
|
|
2140
|
+
});
|
|
2141
|
+
}
|
|
2142
|
+
}];
|
|
2143
|
+
function isValidVarName(name) {
|
|
2144
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
|
|
2145
|
+
}
|
|
2146
|
+
/**
|
|
2147
|
+
* Generates the final "var" remote entry file
|
|
2148
|
+
* @param remoteEntryFile - Path to esm remote entry file
|
|
2149
|
+
* @returns Complete "var" remoteEntry.js file source
|
|
2150
|
+
*/
|
|
2151
|
+
function generateVarRemoteEntry(remoteEntryFile) {
|
|
2152
|
+
const options = getNormalizeModuleFederationOptions();
|
|
2153
|
+
const {
|
|
2154
|
+
name,
|
|
2155
|
+
varFilename
|
|
2156
|
+
} = options;
|
|
2157
|
+
const isValidName = isValidVarName(name);
|
|
2158
|
+
// todo: implement publicPath/getPublicPath support
|
|
2159
|
+
return `
|
|
2160
|
+
${isValidName ? `var ${name};` : ''}
|
|
2161
|
+
${isValidName ? name : `globalThis['${name}']`} = (function () {
|
|
2162
|
+
function getScriptUrl() {
|
|
2163
|
+
const currentScript = document.currentScript;
|
|
2164
|
+
if (!currentScript) {
|
|
2165
|
+
console.error("[VarRemoteEntry] ${varFilename} script should be called from sync <script> tag (document.currentScript is undefined)")
|
|
2166
|
+
return '/';
|
|
2167
|
+
}
|
|
2168
|
+
return document.currentScript.src.replace(/\\/[^/]*$/, '/');
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
const entry = getScriptUrl() + '${remoteEntryFile}';
|
|
2172
|
+
|
|
2173
|
+
return {
|
|
2174
|
+
get: (...args) => import(entry).then(m => m.get(...args)),
|
|
2175
|
+
init: (...args) => import(entry).then(m => m.init(...args)),
|
|
2176
|
+
};
|
|
2177
|
+
})();
|
|
2178
|
+
`;
|
|
2179
|
+
}
|
|
2180
|
+
};
|
|
2181
|
+
|
|
2017
2182
|
var aliasToArrayPlugin = {
|
|
2018
2183
|
name: 'alias-transform-plugin',
|
|
2019
2184
|
config: (config, {
|
|
@@ -2117,7 +2282,7 @@ function federation(mfUserOptions) {
|
|
|
2117
2282
|
(_config$optimizeDeps3 = config.optimizeDeps) == null || (_config$optimizeDeps3 = _config$optimizeDeps3.needsInterop) == null || _config$optimizeDeps3.push(virtualDir);
|
|
2118
2283
|
(_config$optimizeDeps4 = config.optimizeDeps) == null || (_config$optimizeDeps4 = _config$optimizeDeps4.needsInterop) == null || _config$optimizeDeps4.push(getLocalSharedImportMapPath());
|
|
2119
2284
|
}
|
|
2120
|
-
}, ...Manifest()];
|
|
2285
|
+
}, ...Manifest(), ...VarRemoteEntry()];
|
|
2121
2286
|
}
|
|
2122
2287
|
|
|
2123
2288
|
export { federation };
|
package/lib/index.umd.js
CHANGED
|
@@ -145,15 +145,44 @@
|
|
|
145
145
|
}
|
|
146
146
|
},
|
|
147
147
|
generateBundle: function generateBundle(options, bundle) {
|
|
148
|
-
var _viteConfig$experimen, _viteConfig$experimen2;
|
|
149
148
|
if (!injectHtml()) return;
|
|
150
149
|
var file = this.getFileName(emitFileId);
|
|
151
|
-
|
|
152
|
-
var
|
|
150
|
+
// Helper to resolve path with proper renderBuiltUrl handling
|
|
151
|
+
var resolvePath = function resolvePath(htmlFileName) {
|
|
152
|
+
var _viteConfig$experimen;
|
|
153
|
+
if (!((_viteConfig$experimen = viteConfig.experimental) != null && _viteConfig$experimen.renderBuiltUrl)) {
|
|
154
|
+
return viteConfig.base + file;
|
|
155
|
+
}
|
|
156
|
+
var result = viteConfig.experimental.renderBuiltUrl(file, {
|
|
157
|
+
hostId: htmlFileName,
|
|
158
|
+
hostType: 'html',
|
|
159
|
+
type: 'asset',
|
|
160
|
+
ssr: false
|
|
161
|
+
});
|
|
162
|
+
// Handle return types
|
|
163
|
+
if (typeof result === 'string') {
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
if (result && typeof result === 'object') {
|
|
167
|
+
if ('runtime' in result) {
|
|
168
|
+
// Runtime code cannot be used in <script src="">
|
|
169
|
+
console.warn('[vite-plugin-federation] renderBuiltUrl returned runtime code for HTML injection. ' + 'Runtime code cannot be used in <script src="">. Falling back to base path.');
|
|
170
|
+
return viteConfig.base + file;
|
|
171
|
+
}
|
|
172
|
+
if (result.relative) {
|
|
173
|
+
return file;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Fallback for undefined or unexpected values
|
|
177
|
+
return viteConfig.base + file;
|
|
178
|
+
};
|
|
179
|
+
// Process each HTML file
|
|
153
180
|
for (var _fileName in bundle) {
|
|
154
181
|
if (_fileName.endsWith('.html')) {
|
|
155
182
|
var htmlAsset = bundle[_fileName];
|
|
156
183
|
if (htmlAsset.type === 'chunk') return;
|
|
184
|
+
var _path = resolvePath(_fileName);
|
|
185
|
+
var scriptContent = "\n <script type=\"module\" src=\"" + _path + "\"></script>\n ";
|
|
157
186
|
var htmlContent = htmlAsset.source.toString() || '';
|
|
158
187
|
htmlContent = htmlContent.replace('<head>', "<head>" + scriptContent);
|
|
159
188
|
htmlAsset.source = htmlContent;
|
|
@@ -873,7 +902,8 @@
|
|
|
873
902
|
virtualModuleDir: options.virtualModuleDir || '__mf__virtual',
|
|
874
903
|
hostInitInjectLocation: options.hostInitInjectLocation || 'html',
|
|
875
904
|
bundleAllCSS: options.bundleAllCSS || false,
|
|
876
|
-
moduleParseTimeout: options.moduleParseTimeout || 10
|
|
905
|
+
moduleParseTimeout: options.moduleParseTimeout || 10,
|
|
906
|
+
varFilename: options.varFilename
|
|
877
907
|
};
|
|
878
908
|
}
|
|
879
909
|
|
|
@@ -1284,6 +1314,16 @@
|
|
|
1284
1314
|
writeRuntimeInitStatus();
|
|
1285
1315
|
}
|
|
1286
1316
|
|
|
1317
|
+
function findRemoteEntryFile(filename, bundle) {
|
|
1318
|
+
for (var _i = 0, _Object$entries = Object.entries(bundle); _i < _Object$entries.length; _i++) {
|
|
1319
|
+
var _Object$entries$_i = _Object$entries[_i],
|
|
1320
|
+
fileData = _Object$entries$_i[1];
|
|
1321
|
+
if (filename.replace(/[\[\]]/g, '_').replace(/\.[^/.]+$/, '') === fileData.name || fileData.name === 'remoteEntry') {
|
|
1322
|
+
return fileData.fileName; // We can return early since we only need to find remoteEntry once
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1287
1327
|
var ASSET_TYPES = ['js', 'css'];
|
|
1288
1328
|
var LOAD_TIMINGS = ['sync', 'async'];
|
|
1289
1329
|
var JS_EXTENSIONS = ['.ts', '.tsx', '.jsx', '.mjs', '.cjs'];
|
|
@@ -1461,7 +1501,8 @@
|
|
|
1461
1501
|
var name = mfOptions.name,
|
|
1462
1502
|
filename = mfOptions.filename,
|
|
1463
1503
|
getPublicPath = mfOptions.getPublicPath,
|
|
1464
|
-
manifestOptions = mfOptions.manifest
|
|
1504
|
+
manifestOptions = mfOptions.manifest,
|
|
1505
|
+
varFilename = mfOptions.varFilename;
|
|
1465
1506
|
var mfManifestName = '';
|
|
1466
1507
|
if (manifestOptions === true) {
|
|
1467
1508
|
mfManifestName = 'mf-manifest.json';
|
|
@@ -1534,6 +1575,11 @@
|
|
|
1534
1575
|
path: '',
|
|
1535
1576
|
type: 'module'
|
|
1536
1577
|
},
|
|
1578
|
+
varRemoteEntry: varFilename ? {
|
|
1579
|
+
name: varFilename,
|
|
1580
|
+
path: '',
|
|
1581
|
+
type: 'var'
|
|
1582
|
+
} : undefined,
|
|
1537
1583
|
types: {
|
|
1538
1584
|
path: '',
|
|
1539
1585
|
name: ''
|
|
@@ -1583,15 +1629,10 @@
|
|
|
1583
1629
|
var _this = this;
|
|
1584
1630
|
if (!mfManifestName) return Promise.resolve();
|
|
1585
1631
|
var filesMap = {};
|
|
1632
|
+
var foundRemoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
|
|
1586
1633
|
// First pass: Find remoteEntry file
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
_ = _Object$entries$_i[0],
|
|
1590
|
-
fileData = _Object$entries$_i[1];
|
|
1591
|
-
if (mfOptions.filename.replace(/[\[\]]/g, '_').replace(/\.[^/.]+$/, '') === fileData.name || fileData.name === 'remoteEntry') {
|
|
1592
|
-
remoteEntryFile = fileData.fileName;
|
|
1593
|
-
break; // We can break early since we only need to find remoteEntry once
|
|
1594
|
-
}
|
|
1634
|
+
if (foundRemoteEntryFile) {
|
|
1635
|
+
remoteEntryFile = foundRemoteEntryFile;
|
|
1595
1636
|
}
|
|
1596
1637
|
// Second pass: Collect all CSS assets
|
|
1597
1638
|
var allCssAssets = mfOptions.bundleAllCSS ? collectCssAssets(bundle) : new Set();
|
|
@@ -1646,12 +1687,18 @@
|
|
|
1646
1687
|
*/
|
|
1647
1688
|
function generateMFManifest(preloadMap) {
|
|
1648
1689
|
var options = getNormalizeModuleFederationOptions();
|
|
1649
|
-
var name = options.name
|
|
1690
|
+
var name = options.name,
|
|
1691
|
+
varFilename = options.varFilename;
|
|
1650
1692
|
var remoteEntry = {
|
|
1651
1693
|
name: remoteEntryFile,
|
|
1652
1694
|
path: '',
|
|
1653
1695
|
type: 'module'
|
|
1654
1696
|
};
|
|
1697
|
+
var varRemoteEntry = varFilename ? {
|
|
1698
|
+
name: varFilename,
|
|
1699
|
+
path: '',
|
|
1700
|
+
type: 'module'
|
|
1701
|
+
} : undefined;
|
|
1655
1702
|
// Process remotes
|
|
1656
1703
|
var remotes = Array.from(Object.entries(getUsedRemotesMap())).flatMap(function (_ref2) {
|
|
1657
1704
|
var remoteKey = _ref2[0],
|
|
@@ -1721,6 +1768,7 @@
|
|
|
1721
1768
|
},
|
|
1722
1769
|
remoteEntry: remoteEntry,
|
|
1723
1770
|
ssrRemoteEntry: remoteEntry,
|
|
1771
|
+
varRemoteEntry: varRemoteEntry,
|
|
1724
1772
|
types: {
|
|
1725
1773
|
path: '',
|
|
1726
1774
|
name: ''
|
|
@@ -2010,6 +2058,103 @@
|
|
|
2010
2058
|
}];
|
|
2011
2059
|
}
|
|
2012
2060
|
|
|
2061
|
+
var VarRemoteEntry = function VarRemoteEntry() {
|
|
2062
|
+
var mfOptions = getNormalizeModuleFederationOptions();
|
|
2063
|
+
var name = mfOptions.name,
|
|
2064
|
+
varFilename = mfOptions.varFilename,
|
|
2065
|
+
filename = mfOptions.filename;
|
|
2066
|
+
var viteConfig;
|
|
2067
|
+
return [{
|
|
2068
|
+
name: 'module-federation-var-remote-entry',
|
|
2069
|
+
apply: 'serve',
|
|
2070
|
+
/**
|
|
2071
|
+
* Stores resolved Vite config for later use
|
|
2072
|
+
*/
|
|
2073
|
+
/**
|
|
2074
|
+
* Finalizes configuration after all plugins are resolved
|
|
2075
|
+
* @param config - Fully resolved Vite config
|
|
2076
|
+
*/
|
|
2077
|
+
configResolved: function configResolved(config) {
|
|
2078
|
+
viteConfig = config;
|
|
2079
|
+
},
|
|
2080
|
+
/**
|
|
2081
|
+
* Configures dev server middleware to handle varRemoteEntry requests
|
|
2082
|
+
* @param server - Vite dev server instance
|
|
2083
|
+
*/
|
|
2084
|
+
configureServer: function configureServer(server) {
|
|
2085
|
+
server.middlewares.use(function (req, res, next) {
|
|
2086
|
+
var _req$url;
|
|
2087
|
+
if (!varFilename) {
|
|
2088
|
+
next();
|
|
2089
|
+
return;
|
|
2090
|
+
}
|
|
2091
|
+
if (((_req$url = req.url) == null ? void 0 : _req$url.replace(/\?.*/, '')) === (viteConfig.base + varFilename).replace(/^\/?/, '/')) {
|
|
2092
|
+
res.setHeader('Content-Type', 'text/javascript');
|
|
2093
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
2094
|
+
console.log({
|
|
2095
|
+
filename: filename
|
|
2096
|
+
});
|
|
2097
|
+
res.end(generateVarRemoteEntry(filename));
|
|
2098
|
+
} else {
|
|
2099
|
+
next();
|
|
2100
|
+
}
|
|
2101
|
+
});
|
|
2102
|
+
}
|
|
2103
|
+
}, {
|
|
2104
|
+
name: 'module-federation-var-remote-entry',
|
|
2105
|
+
enforce: 'post',
|
|
2106
|
+
/**
|
|
2107
|
+
* Initial plugin configuration
|
|
2108
|
+
* @param config - Vite config object
|
|
2109
|
+
* @param command - Current Vite command (serve/build)
|
|
2110
|
+
*/
|
|
2111
|
+
config: function config(_config, _ref) {
|
|
2112
|
+
if (!_config.build) _config.build = {};
|
|
2113
|
+
},
|
|
2114
|
+
/**
|
|
2115
|
+
* Generates the module federation "var" remote entry file
|
|
2116
|
+
* @param options - Rollup output options
|
|
2117
|
+
* @param bundle - Generated bundle assets
|
|
2118
|
+
*/
|
|
2119
|
+
generateBundle: function generateBundle(options, bundle) {
|
|
2120
|
+
try {
|
|
2121
|
+
var _this = this;
|
|
2122
|
+
if (!varFilename) return Promise.resolve();
|
|
2123
|
+
var isValidName = isValidVarName(name);
|
|
2124
|
+
if (!isValidName) {
|
|
2125
|
+
viteConfig.logger.warn("Provided remote name \"" + name + "\" is not valid for \"var\" remoteEntry type, thus it's placed in globalThis['" + name + "'].\nIt may cause problems, so you would better want to use valid var name (see https://www.w3schools.com/js/js_variables.asp).");
|
|
2126
|
+
}
|
|
2127
|
+
var remoteEntryFile = findRemoteEntryFile(mfOptions.filename, bundle);
|
|
2128
|
+
if (!remoteEntryFile) throw new Error("Couldn't find a remoteEntry chunk file for " + mfOptions.filename + ", can't generate varRemoteEntry file");
|
|
2129
|
+
_this.emitFile({
|
|
2130
|
+
type: 'asset',
|
|
2131
|
+
fileName: varFilename,
|
|
2132
|
+
source: generateVarRemoteEntry(remoteEntryFile)
|
|
2133
|
+
});
|
|
2134
|
+
return Promise.resolve();
|
|
2135
|
+
} catch (e) {
|
|
2136
|
+
return Promise.reject(e);
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
}];
|
|
2140
|
+
function isValidVarName(name) {
|
|
2141
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
|
|
2142
|
+
}
|
|
2143
|
+
/**
|
|
2144
|
+
* Generates the final "var" remote entry file
|
|
2145
|
+
* @param remoteEntryFile - Path to esm remote entry file
|
|
2146
|
+
* @returns Complete "var" remoteEntry.js file source
|
|
2147
|
+
*/
|
|
2148
|
+
function generateVarRemoteEntry(remoteEntryFile) {
|
|
2149
|
+
var options = getNormalizeModuleFederationOptions();
|
|
2150
|
+
var name = options.name,
|
|
2151
|
+
varFilename = options.varFilename;
|
|
2152
|
+
var isValidName = isValidVarName(name);
|
|
2153
|
+
// todo: implement publicPath/getPublicPath support
|
|
2154
|
+
return "\n " + (isValidName ? "var " + name + ";" : '') + "\n " + (isValidName ? name : "globalThis['" + name + "']") + " = (function () {\n function getScriptUrl() {\n const currentScript = document.currentScript;\n if (!currentScript) {\n console.error(\"[VarRemoteEntry] " + varFilename + " script should be called from sync <script> tag (document.currentScript is undefined)\")\n return '/';\n }\n return document.currentScript.src.replace(/\\/[^/]*$/, '/');\n }\n\n const entry = getScriptUrl() + '" + remoteEntryFile + "';\n\n return {\n get: (...args) => import(entry).then(m => m.get(...args)),\n init: (...args) => import(entry).then(m => m.init(...args)),\n };\n })();\n ";
|
|
2155
|
+
}
|
|
2156
|
+
};
|
|
2157
|
+
|
|
2013
2158
|
var aliasToArrayPlugin = {
|
|
2014
2159
|
name: 'alias-transform-plugin',
|
|
2015
2160
|
config: function config(_config, _ref) {
|
|
@@ -2104,7 +2249,7 @@
|
|
|
2104
2249
|
(_config$optimizeDeps3 = _config.optimizeDeps) == null || (_config$optimizeDeps3 = _config$optimizeDeps3.needsInterop) == null || _config$optimizeDeps3.push(virtualDir);
|
|
2105
2250
|
(_config$optimizeDeps4 = _config.optimizeDeps) == null || (_config$optimizeDeps4 = _config$optimizeDeps4.needsInterop) == null || _config$optimizeDeps4.push(getLocalSharedImportMapPath());
|
|
2106
2251
|
}
|
|
2107
|
-
}], Manifest());
|
|
2252
|
+
}], Manifest(), VarRemoteEntry());
|
|
2108
2253
|
}
|
|
2109
2254
|
|
|
2110
2255
|
exports.federation = federation;
|
|
@@ -72,6 +72,10 @@ export type ModuleFederationOptions = {
|
|
|
72
72
|
* Defaults to 10 seconds.
|
|
73
73
|
*/
|
|
74
74
|
moduleParseTimeout?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Allows generate additional remoteEntry file for "var" host environment
|
|
77
|
+
*/
|
|
78
|
+
varFilename?: string;
|
|
75
79
|
};
|
|
76
80
|
export interface NormalizedModuleFederationOptions {
|
|
77
81
|
exposes: Record<string, ExposesItem>;
|
|
@@ -100,6 +104,7 @@ export interface NormalizedModuleFederationOptions {
|
|
|
100
104
|
*/
|
|
101
105
|
bundleAllCSS: boolean;
|
|
102
106
|
moduleParseTimeout: number;
|
|
107
|
+
varFilename?: string;
|
|
103
108
|
}
|
|
104
109
|
type HostInitInjectLocationOptions = 'entry' | 'html';
|
|
105
110
|
interface PluginDevOptions {
|