@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 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
- var path = (_viteConfig$experimen = viteConfig.experimental) != null && _viteConfig$experimen.renderBuiltUrl ? (_viteConfig$experimen2 = viteConfig.experimental) == null ? void 0 : _viteConfig$experimen2.renderBuiltUrl(file) : viteConfig.base + file;
157
- var scriptContent = "\n <script type=\"module\" src=\"" + path + "\"></script>\n ";
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
- for (var _i = 0, _Object$entries = Object.entries(bundle); _i < _Object$entries.length; _i++) {
1593
- var _Object$entries$_i = _Object$entries[_i],
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
- var path = (_viteConfig$experimen = viteConfig.experimental) != null && _viteConfig$experimen.renderBuiltUrl ? (_viteConfig$experimen2 = viteConfig.experimental) == null ? void 0 : _viteConfig$experimen2.renderBuiltUrl(file) : viteConfig.base + file;
133
- var scriptContent = "\n <script type=\"module\" src=\"" + path + "\"></script>\n ";
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
- for (var _i = 0, _Object$entries = Object.entries(bundle); _i < _Object$entries.length; _i++) {
1569
- var _Object$entries$_i = _Object$entries[_i],
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 };
@@ -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
- const path = (_viteConfig$experimen = viteConfig.experimental) != null && _viteConfig$experimen.renderBuiltUrl ? (_viteConfig$experimen2 = viteConfig.experimental) == null ? void 0 : _viteConfig$experimen2.renderBuiltUrl(file) : viteConfig.base + file;
131
- const scriptContent = `
132
- <script type="module" src="${path}"></script>
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
- for (const [_, fileData] of Object.entries(bundle)) {
1615
- if (mfOptions.filename.replace(/[\[\]]/g, '_').replace(/\.[^/.]+$/, '') === fileData.name || fileData.name === 'remoteEntry') {
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
- var path = (_viteConfig$experimen = viteConfig.experimental) != null && _viteConfig$experimen.renderBuiltUrl ? (_viteConfig$experimen2 = viteConfig.experimental) == null ? void 0 : _viteConfig$experimen2.renderBuiltUrl(file) : viteConfig.base + file;
152
- var scriptContent = "\n <script type=\"module\" src=\"" + path + "\"></script>\n ";
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
- for (var _i = 0, _Object$entries = Object.entries(bundle); _i < _Object$entries.length; _i++) {
1588
- var _Object$entries$_i = _Object$entries[_i],
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;
@@ -0,0 +1,3 @@
1
+ import { Plugin } from 'vite';
2
+ declare const VarRemoteEntry: () => Plugin[];
3
+ export default VarRemoteEntry;
@@ -0,0 +1,2 @@
1
+ import { OutputBundle } from 'rollup';
2
+ export declare function findRemoteEntryFile(filename: string, bundle: OutputBundle): string | undefined;
@@ -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 {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@module-federation/vite",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "description": "Vite plugin for Module Federation",
5
5
  "type": "module",
6
6
  "source": "src/index.ts",