@module-federation/node
Advanced tools
Comparing version 0.15.1 to 0.15.2-rc.0
179
CHANGELOG.md
@@ -5,2 +5,181 @@ # Changelog | ||
## [0.15.2-rc.0](https://github.com/module-federation/nextjs-mf/compare/node-0.15.1...node-0.15.2-rc.0) (2023-05-23) | ||
### Bug Fixes | ||
* chunk and module duplications ([#885](https://github.com/module-federation/nextjs-mf/issues/885)) ([199e6b9](https://github.com/module-federation/nextjs-mf/commit/199e6b9937f4a2ca6caedb3ae4767342de463cb6)) | ||
* client prod build issues ([#899](https://github.com/module-federation/nextjs-mf/issues/899)) ([470d7ad](https://github.com/module-federation/nextjs-mf/commit/470d7ad408ae8d64dbccc5a9528eaa2ed60fa2ca)) | ||
* externalization and missing runtime chunks ([#887](https://github.com/module-federation/nextjs-mf/issues/887)) ([c79cd62](https://github.com/module-federation/nextjs-mf/commit/c79cd6226d3134f1d6294cd8eba40c8c33af5cb5)) | ||
* missing chunk hashes on exposed modules ([#893](https://github.com/module-federation/nextjs-mf/issues/893)) ([cfa43f5](https://github.com/module-federation/nextjs-mf/commit/cfa43f506999d5ce3ab6afeea513d50d85f7886e)) | ||
## [0.14.7-rc.2](https://github.com/module-federation/nextjs-mf/compare/node-0.14.7-rc.1...node-0.14.7-rc.2) (2023-05-17) | ||
## [0.14.7-rc.1](https://github.com/module-federation/nextjs-mf/compare/node-0.14.7-rc.0...node-0.14.7-rc.1) (2023-05-17) | ||
### Bug Fixes | ||
* **chunk-module-duplication:** prevent runtime reset and share scope loss ([14bfc38](https://github.com/module-federation/nextjs-mf/commit/14bfc38515a4da3be7321d4b6d876905d45ad20b)) | ||
## [0.14.7-rc.0](https://github.com/module-federation/nextjs-mf/compare/node-0.14.7-beta.3...node-0.14.7-rc.0) (2023-05-16) | ||
## [0.14.7-beta.3](https://github.com/module-federation/nextjs-mf/compare/node-0.14.7-beta.2...node-0.14.7-beta.3) (2023-05-16) | ||
## [0.14.7-beta.2](https://github.com/module-federation/nextjs-mf/compare/node-0.14.7-beta.1...node-0.14.7-beta.2) (2023-05-16) | ||
## [0.14.7-beta.1](https://github.com/module-federation/nextjs-mf/compare/node-0.14.7-beta.0...node-0.14.7-beta.1) (2023-05-16) | ||
## [0.14.7-beta.0](https://github.com/module-federation/nextjs-mf/compare/node-0.14.6...node-0.14.7-beta.0) (2023-05-16) | ||
## [0.14.6](https://github.com/module-federation/nextjs-mf/compare/node-0.14.5...node-0.14.6) (2023-05-16) | ||
## [0.14.5](https://github.com/module-federation/nextjs-mf/compare/node-0.14.5-beta.0...node-0.14.5) (2023-05-15) | ||
## [0.14.5-beta.0](https://github.com/module-federation/nextjs-mf/compare/node-0.14.4...node-0.14.5-beta.0) (2023-05-15) | ||
### Features | ||
* Quantum Modules ([#872](https://github.com/module-federation/nextjs-mf/issues/872)) ([2991039](https://github.com/module-federation/nextjs-mf/commit/299103932b4e0aa6d8017be588ffa5272f519260)) | ||
## [0.14.4](https://github.com/module-federation/nextjs-mf/compare/node-0.14.4-beta.0...node-0.14.4) (2023-05-13) | ||
## [0.14.4-beta.0](https://github.com/module-federation/nextjs-mf/compare/node-0.14.3...node-0.14.4-beta.0) (2023-05-13) | ||
### Bug Fixes | ||
* remove container proxy code ([6123d98](https://github.com/module-federation/nextjs-mf/commit/6123d9846606d76be949492ca04474f5c8164bc7)) | ||
### Features | ||
* [7] Async boundary runtime server ([#851](https://github.com/module-federation/nextjs-mf/issues/851)) ([7fa792a](https://github.com/module-federation/nextjs-mf/commit/7fa792a4b518cd007b5ac41db225e20521063e73)), closes [#864](https://github.com/module-federation/nextjs-mf/issues/864) | ||
### BREAKING CHANGES | ||
* automaticAsyncBoundary option has been removed | ||
* fix: exclude specific pages from page map automatically | ||
* refactor: conslidate codebase | ||
* fix: improve hot reload share recovery | ||
* refactor: remove server jsonp template | ||
* chore: remove dead code from runtime modules | ||
* fix: clean up jsonp getCustomJsonpCode | ||
getting chunk loading global from compiler output options | ||
* feat: adding cleanInitArrays runtime helper | ||
* chore: remove share scope hoist and module hoisting system | ||
* chore: cleanup code | ||
## [0.14.3](https://github.com/module-federation/nextjs-mf/compare/node-0.14.3-beta.0...node-0.14.3) (2023-05-03) | ||
## [0.14.3-beta.0](https://github.com/module-federation/nextjs-mf/compare/node-0.14.2...node-0.14.3-beta.0) (2023-05-03) | ||
## [0.14.2](https://github.com/module-federation/nextjs-mf/compare/node-0.14.2-beta.1...node-0.14.2) (2023-04-28) | ||
## [0.14.2-beta.1](https://github.com/module-federation/nextjs-mf/compare/node-0.14.2-beta.0...node-0.14.2-beta.1) (2023-04-28) | ||
## [0.14.2-beta.0](https://github.com/module-federation/nextjs-mf/compare/node-0.14.1...node-0.14.2-beta.0) (2023-04-28) | ||
### Bug Fixes | ||
* use [fullhash] if no hash exists / in development mode. ([dfa7fb3](https://github.com/module-federation/nextjs-mf/commit/dfa7fb3a49b81b87dae43ec57ff2f86f5c2b7501)) | ||
## [0.14.1](https://github.com/module-federation/nextjs-mf/compare/node-0.14.1-beta.0...node-0.14.1) (2023-04-28) | ||
## [0.14.1-beta.0](https://github.com/module-federation/nextjs-mf/compare/node-0.14.0...node-0.14.1-beta.0) (2023-04-28) | ||
### Features | ||
* Improve module chunk connections ([#802](https://github.com/module-federation/nextjs-mf/issues/802)) ([ce0bd7b](https://github.com/module-federation/nextjs-mf/commit/ce0bd7b16e080f712e6db0bdcd3955a8167c274f)), closes [#803](https://github.com/module-federation/nextjs-mf/issues/803) [#808](https://github.com/module-federation/nextjs-mf/issues/808) [#811](https://github.com/module-federation/nextjs-mf/issues/811) | ||
## [0.13.1](https://github.com/module-federation/nextjs-mf/compare/node-0.13.1-beta.0...node-0.13.1) (2023-04-19) | ||
## [0.13.1-beta.0](https://github.com/module-federation/nextjs-mf/compare/node-0.13.0...node-0.13.1-beta.0) (2023-04-19) | ||
### Bug Fixes | ||
* use container proxy on script VM instead of host resolver point ([2929d0f](https://github.com/module-federation/nextjs-mf/commit/2929d0f64d4b8edf268af5ca83f807a02b121861)) | ||
* get delegates working ([#527](https://github.com/module-federation/nextjs-mf/issues/527)) ([7655568](https://github.com/module-federation/nextjs-mf/commit/7655568fcef8dbfda40573deb5d3d029c101074c)) | ||
* improved asset pipeline ([63928b2](https://github.com/module-federation/nextjs-mf/commit/63928b28150c2c4e3adb9e14fb7aa54f5cf1578d)) | ||
* peer dependencies metadata ([d3a2ed0](https://github.com/module-federation/nextjs-mf/commit/d3a2ed0e378b59afdeb632d1e2e0290f05cbca19)) | ||
* solve externalization ([49f52e5](https://github.com/module-federation/nextjs-mf/commit/49f52e53ddddc990d31e6aa510d67dc0552a9d9a)) | ||
* use EntryPlugin for injection of remotes ([e522c5a](https://github.com/module-federation/nextjs-mf/commit/e522c5ad2b7adcbd6c39f9c5fdb7a3e418277b7a)) | ||
### Features | ||
* delegate module support ([5061d3d](https://github.com/module-federation/nextjs-mf/commit/5061d3d64d7d83dbb25b4ef2378d434545186cb1)) | ||
* chunk flushing in delegates ([5e2375f](https://github.com/module-federation/nextjs-mf/commit/5e2375f598437803105ac4bc2237f6b652554d00)) | ||
* delegate module support ([8dd154c](https://github.com/module-federation/nextjs-mf/commit/8dd154c261b34183b12250ce204904cd3e085658)) | ||
* delegate module support ([d242163](https://github.com/module-federation/nextjs-mf/commit/d24216324183bfec5c7ba672ba6da05679f67809)) | ||
* delegates part two ([1be2686](https://github.com/module-federation/nextjs-mf/commit/1be2686624798a7df9f447b48279294985b3f592)) | ||
* improve chunk correlation ([22d8afc](https://github.com/module-federation/nextjs-mf/commit/22d8afccff101044fcdeba390656950dbc6eafed)) | ||
* new chunk flushing system for exposed modules ([97a75d8](https://github.com/module-federation/nextjs-mf/commit/97a75d8702f2ddc5e12cff2ac4d24aca1df6f990)) | ||
* prepare for v7 ([7bc4b3b](https://github.com/module-federation/nextjs-mf/commit/7bc4b3bd44e0926a52d6a9cbe56f0c4d7bb700ae)) | ||
### BREAKING CHANGES | ||
* safety breaking change note | ||
BREAKING_CHANGE: safety breaking change note | ||
## [0.15.1](https://github.com/module-federation/nextjs-mf/compare/node-0.15.0...node-0.15.1) (2023-05-22) | ||
@@ -7,0 +186,0 @@ |
{ | ||
"public": true, | ||
"name": "@module-federation/node", | ||
"version": "0.15.1", | ||
"version": "0.15.2-rc.0", | ||
"type": "commonjs", | ||
@@ -38,3 +38,4 @@ "main": "src/index.js", | ||
"node-fetch": "^2.6.7", | ||
"@module-federation/utilities": "1.8.0" | ||
"@module-federation/utilities": "1.8.1-rc.1", | ||
"webpack-sources": "3.2.3" | ||
}, | ||
@@ -41,0 +42,0 @@ "peerDependencies": { |
@@ -59,4 +59,11 @@ "use strict"; | ||
function getExposedModules(stats, exposedFile) { | ||
return stats.modules.filter((mod) => mod.name.startsWith(exposedFile)); | ||
return stats.modules.filter((mod) => mod.name?.startsWith(exposedFile)); | ||
} | ||
function getDependenciesOfChunk(stats, chunk) { | ||
return stats.chunks | ||
.filter((c) => c.children.includes(chunk.id)) | ||
.reduce((acc, c) => { | ||
return acc.concat(c.modules); | ||
}, []); | ||
} | ||
/** | ||
@@ -69,5 +76,21 @@ * | ||
function getExposed(stats, mod) { | ||
const chunks = stats.chunks.filter((chunk) => mod.chunks.some((id) => id === chunk.id)); | ||
const chunks = stats.chunks.filter((chunk) => { | ||
return chunk.modules.find((modsInChunk) => { | ||
return modsInChunk.id === mod.id && !modsInChunk.dependent; | ||
}); | ||
}); | ||
const dependencies = stats.modules | ||
.filter((sharedModule) => { | ||
if (sharedModule.moduleType !== 'consume-shared-module') | ||
return false; | ||
return sharedModule.issuerId === mod.id; | ||
}) | ||
.map((sharedModule) => { | ||
return sharedModule.identifier.split('|')[2]; | ||
}); | ||
const flatChunks = flatMap(chunks, (chunk) => ({ | ||
[chunk.id]: chunk.files.map((f) => `${stats.publicPath === 'auto' ? '' : stats.publicPath || ''}${f}`), | ||
[chunk.id]: { | ||
files: chunk.files.map((f) => `${stats.publicPath === 'auto' ? '' : stats.publicPath || ''}${f}`), | ||
requiredModules: dependencies, | ||
}, | ||
})); | ||
@@ -91,2 +114,14 @@ return flatChunks.reduce((acc, chunk) => { | ||
} | ||
function searchReason(mod, check) { | ||
if (mod.reasons && check(mod.reasons)) { | ||
return true; | ||
} | ||
return !!mod.reasons && mod.reasons.some((m) => searchReason(m, check)); | ||
} | ||
function searchIssuerAndReason(mod, check) { | ||
const foundIssuer = searchIssuer(mod, (issuer) => check(issuer)); | ||
if (foundIssuer) | ||
return foundIssuer; | ||
return searchReason(mod, (reason) => reason.some((r) => check(r?.moduleIdentifier))); | ||
} | ||
/** | ||
@@ -105,2 +140,23 @@ * @param {import("webpack").Module} mod | ||
} | ||
function getIssuersAndReasons(mod, check) { | ||
if (mod.issuer && check(mod.issuer)) { | ||
return [mod.issuer]; | ||
} | ||
if (mod.reasons && | ||
searchReason(mod, (reason) => reason.some((r) => check(r?.moduleIdentifier)))) { | ||
return mod.reasons | ||
.filter((r) => { | ||
return r.moduleIdentifier && check(r.moduleIdentifier); | ||
}) | ||
.map((r) => r.moduleIdentifier); | ||
} | ||
return ((mod.modules && | ||
mod.modules | ||
.filter((m) => searchIssuerAndReason(m, check)) | ||
.map((m) => { | ||
return (m.issuer || | ||
m.reasons.find((r) => check(r?.moduleIdentifier)).moduleIdentifier); | ||
})) || | ||
[]); | ||
} | ||
/** | ||
@@ -133,9 +189,9 @@ * @param {string} issuer | ||
return flatMap(stats.chunks.filter((chunk) => { | ||
if (!stats.entrypoints[federationPlugin._options.name]) { | ||
if (!stats.entrypoints[federationPlugin.name]) { | ||
return false; | ||
} | ||
return stats.entrypoints[federationPlugin._options.name].chunks.some((id) => chunk.id === id); | ||
return stats.entrypoints[federationPlugin.name].chunks.some((id) => chunk.id === id); | ||
}), (chunk) => flatMap(chunk.children, (id) => stats.chunks.filter((c) => c.id === id && | ||
c.files.length > 0 && | ||
c.parents.some((p) => stats.entrypoints[federationPlugin._options.name].chunks.some((c) => c === p)) && | ||
c.parents.some((p) => stats.entrypoints[federationPlugin.name].chunks.some((c) => c === p)) && | ||
c.modules.some((m) => searchIssuer(m, (issuer) => issuer?.startsWith('consume-shared-module')))))) | ||
@@ -158,11 +214,17 @@ .map((chunk) => ({ | ||
: []; | ||
return flatMap(chunks, (chunk) => flatMap(chunk.children, (id) => stats.chunks.filter((c) => c.id === id && | ||
c.files.length > 0 && | ||
c.modules.some((m) => searchIssuer(m, (issuer) => issuer?.startsWith('consume-shared-module')))))) | ||
.map((chunk) => ({ | ||
chunks: chunk.files.map((f) => `${stats.publicPath === 'auto' ? '' : stats.publicPath || ''}${f}`), | ||
provides: flatMap(chunk.modules.filter((m) => searchIssuer(m, (issuer) => issuer?.startsWith('consume-shared-module'))), (m) => getIssuers(m, (issuer) => issuer?.startsWith('consume-shared-module'))) | ||
.map(parseFederatedIssuer) | ||
.filter((f) => !!f), | ||
})) | ||
return flatMap(chunks, (chunk) => flatMap(chunk.children, (id) => stats.chunks.filter((c) => { | ||
return (c.id === id && | ||
c.files.length > 0 && | ||
c.modules.some((m) => { | ||
return searchIssuerAndReason(m, (check) => check?.startsWith('consume-shared-module')); | ||
})); | ||
}))) | ||
.map((chunk) => { | ||
return { | ||
chunks: chunk.files.map((f) => `${stats.publicPath === 'auto' ? '' : stats.publicPath || ''}${f}`), | ||
provides: flatMap(chunk.modules.filter((m) => searchIssuerAndReason(m, (check) => check?.startsWith('consume-shared-module'))), (m) => getIssuersAndReasons(m, (issuer) => issuer?.startsWith('consume-shared-module'))) | ||
.map(parseFederatedIssuer) | ||
.filter((f) => !!f), | ||
}; | ||
}) | ||
.filter((c) => c.provides.length > 0); | ||
@@ -176,4 +238,4 @@ } | ||
*/ | ||
function getFederationStats(stats, federationPlugin) { | ||
const exposedModules = Object.entries(federationPlugin._options.exposes).reduce((exposedModules, [exposedAs, exposedFile]) => Object.assign(exposedModules, { | ||
function getFederationStats(stats, federationPluginOptions) { | ||
const exposedModules = Object.entries(federationPluginOptions.exposes).reduce((exposedModules, [exposedAs, exposedFile]) => Object.assign(exposedModules, { | ||
[exposedAs]: getExposedModules(stats, exposedFile), | ||
@@ -186,4 +248,4 @@ }), {}); | ||
/** @type {string} */ | ||
const remote = federationPlugin._options.library?.name || federationPlugin._options.name; | ||
const sharedModules = getSharedModules(stats, federationPlugin); | ||
const remote = federationPluginOptions.library?.name || federationPluginOptions.name; | ||
const sharedModules = getSharedModules(stats, federationPluginOptions); | ||
const remoteModules = getRemoteModules(stats); | ||
@@ -195,3 +257,3 @@ return { | ||
? stats.assetsByChunkName[remote][0] | ||
: federationPlugin._options.filename}`, | ||
: federationPluginOptions.filename}`, | ||
sharedModules, | ||
@@ -235,27 +297,89 @@ exposes, | ||
} | ||
let alreadyRun = false; | ||
compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => { | ||
compilation.hooks.processAssets.tapPromise({ | ||
compilation.hooks.processAssets.tap({ | ||
name: PLUGIN_NAME, | ||
stage: compilation.constructor.PROCESS_ASSETS_STAGE_ANALYSE, | ||
}, async () => { | ||
stage: compilation.constructor.PROCESS_ASSETS_STAGE_REPORT, | ||
}, | ||
// PLUGIN_NAME, | ||
async () => { | ||
const [federationOpts] = federationPlugins.map((federationPlugin) => { | ||
return federationPlugin?._options; | ||
}); | ||
let container; | ||
for (const [name, entry] of compilation.entrypoints) { | ||
if (container) | ||
break; | ||
federationOpts.name.includes(name) && (container = entry); | ||
} | ||
if (!container) | ||
return; | ||
container = container?.getEntrypointChunk(); | ||
const [containerEntryModule] = Array.from(compilation.chunkGraph.getChunkEntryModulesIterable(container)); | ||
const exposedObj = Object.fromEntries(containerEntryModule._exposes); | ||
const moduleMap = {}; | ||
for (let mod of compilation.modules) { | ||
if (mod.rawRequest) | ||
moduleMap[mod.rawRequest] = mod; | ||
} | ||
const exposedResolved = {}; | ||
for (let exposed in exposedObj) { | ||
exposedResolved[exposed] = moduleMap[exposedObj[exposed].import]; | ||
} | ||
const builtExposes = {}; | ||
container.getAllAsyncChunks().forEach((chunk) => { | ||
for (let expose in exposedResolved) { | ||
const rootModulesInChunk = compilation.chunkGraph.getChunkRootModules(chunk); | ||
if (rootModulesInChunk.includes(exposedResolved[expose])) { | ||
const referencedChunks = chunk.getAllReferencedChunks(); | ||
const currentModule = exposedResolved[expose]; | ||
if (!builtExposes[expose]) | ||
builtExposes[expose] = []; | ||
referencedChunks.forEach((chunk) => { | ||
const rootReferencesInChunk = compilation.chunkGraph.getChunkRootModules(chunk); | ||
const isNodeModule = rootReferencesInChunk.some((mod) => { | ||
if (mod.rootModule) | ||
mod = mod.rootModule; | ||
return mod?.resource?.includes('node_modules'); | ||
}); | ||
if (isNodeModule) | ||
return; | ||
builtExposes[expose] = [ | ||
...builtExposes[expose], | ||
...Array.from(chunk.files), | ||
]; | ||
}); | ||
} | ||
} | ||
}); | ||
const stats = compilation.getStats().toJson({ | ||
performance: false, | ||
time: false, | ||
logging: 'none', | ||
loggingDebug: false, | ||
loggingTrace: false, | ||
source: false, | ||
children: false, | ||
errors: false, | ||
warnings: false, | ||
errorsCount: false, | ||
warningsCount: false, | ||
builtAt: false, | ||
timings: false, | ||
all: false, | ||
assets: true, | ||
reasons: true, | ||
modules: true, | ||
children: true, | ||
chunkGroups: true, | ||
chunkModules: true, | ||
chunkOrigins: false, | ||
entrypoints: true, | ||
namedChunkGroups: false, | ||
chunkRelations: true, | ||
chunks: true, | ||
ids: true, | ||
nestedModules: false, | ||
outputPath: true, | ||
publicPath: true, | ||
}); | ||
const federatedModules = federationPlugins.map((federationPlugin) => getFederationStats(stats, federationPlugin)); | ||
const federatedModules = getFederationStats(stats, federationOpts); | ||
federatedModules.exposes = builtExposes; | ||
const sharedModules = getMainSharedModules(stats); | ||
const vendorChunks = new Set(); | ||
sharedModules.forEach((share) => { | ||
share?.chunks?.forEach((file) => { | ||
vendorChunks.add(file); | ||
}); | ||
}); | ||
const statsResult = { | ||
sharedModules, | ||
federatedModules, | ||
federatedModules: [federatedModules], | ||
}; | ||
@@ -262,0 +386,0 @@ const statsJson = JSON.stringify(statsResult); |
@@ -81,3 +81,12 @@ /* eslint-disable @typescript-eslint/no-var-requires */ | ||
} | ||
for (const c of chunk.getAllAsyncChunks()) { | ||
if (c === chunk || chunkHasJs(c, chunkGraph)) | ||
continue; | ||
if (c.ids) { | ||
for (const id of c.ids) | ||
initialChunkIds.add(id); | ||
} | ||
} | ||
} | ||
console.log('initialChunkIds', initialChunkIds); | ||
return initialChunkIds; | ||
@@ -176,3 +185,2 @@ }; | ||
? webpack_1.Template.indent([ | ||
'', | ||
'var installedChunkData = installedChunks[chunkId];', | ||
@@ -197,2 +205,3 @@ 'if(installedChunkData !== 0) { // 0 means "already installed".', | ||
'if(fs.existsSync(filename)) {', | ||
this._getLogger(`'chunk filename local load', chunkId`), | ||
webpack_1.Template.indent([ | ||
@@ -210,2 +219,3 @@ "fs.readFile(filename, 'utf-8', function(err, content) {", | ||
'} else {', | ||
this._getLogger(`'chunk filename remote load', chunkId`), | ||
webpack_1.Template.indent([ | ||
@@ -257,2 +267,3 @@ loadScript_1.default, | ||
// there may still be a use case for that with promise new promise, depending on how we design it. | ||
`console.log('requestedRemote',requestedRemote, "CURRENT NAME",${JSON.stringify(name)});`, | ||
`var scriptUrl = new URL(requestedRemote);`, | ||
@@ -299,3 +310,6 @@ this._getLogger(`'global.__remote_scope__'`, `global.__remote_scope__`), | ||
'module.exports = __webpack_require__;', | ||
`${webpack_1.RuntimeGlobals.externalInstallChunk} = installChunk;`, | ||
`${webpack_1.RuntimeGlobals.externalInstallChunk} = function(){ | ||
console.log('node: webpack installing to install chunk id:', arguments['0'].id); | ||
return installChunk.apply(this, arguments) | ||
};`, | ||
]) | ||
@@ -302,0 +316,0 @@ : '// no external install chunk', |
@@ -7,2 +7,2 @@ /** | ||
export default _default; | ||
export declare const executeLoadTemplate = "\n function executeLoad(url, callback, name) {\n if(!name) {\n throw new Error('__webpack_require__.l name is required for ' + url);\n }\n\n if (typeof global.__remote_scope__[name] !== 'undefined') return callback(global.__remote_scope__[name]);\n\n const vm = require('vm');\n (global.webpackChunkLoad || global.fetch || require(\"node-fetch\"))(url).then(function (res) {\n return res.text();\n }).then(function (scriptContent) {\n try {\n // TODO: remove conditional in v7, this is to prevent breaking change between v6.0.x and v6.1.x\n const vmContext = typeof URLSearchParams === 'undefined' ?\n {exports, require, module, global, __filename, __dirname, URL, console, process,Buffer, ...global, remoteEntryName: name} :\n {exports, require, module, global, __filename, __dirname, URL, URLSearchParams, console, process,Buffer, ...global, remoteEntryName: name};\n\n const remote = vm.runInNewContext(scriptContent + '\\nmodule.exports', vmContext, {filename: 'node-federation-loader-' + name + '.vm'});\n const foundContainer = remote[name] || remote\n\n if(!global.__remote_scope__[name]) {\n global.__remote_scope__[name] = {\n get: foundContainer.get,\n init: function(initScope, initToken) {\n try {\n foundContainer.init(initScope, initToken)\n } catch (e) {\n // already initialized\n }\n }\n };\n global.__remote_scope__._config[name] = url;\n }\n callback(global.__remote_scope__[name]);\n } catch (e) {\n console.error('executeLoad hit catch block');\n e.target = {src: url};\n callback(e);\n }\n }).catch((e) => {\n e.target = {src: url};\n callback(e);\n });\n }\n"; | ||
export declare const executeLoadTemplate = "\n function executeLoad(url, callback, name) {\n if(!name) {\n throw new Error('__webpack_require__.l name is required for ' + url);\n }\n\n if (typeof global.__remote_scope__[name] !== 'undefined') return callback(global.__remote_scope__[name]);\n console.log('executeLoad', url, name);\n const vm = require('vm');\n (global.webpackChunkLoad || global.fetch || require(\"node-fetch\"))(url).then(function (res) {\n return res.text();\n }).then(function (scriptContent) {\n try {\n // TODO: remove conditional in v7, this is to prevent breaking change between v6.0.x and v6.1.x\n const vmContext = typeof URLSearchParams === 'undefined' ?{exports, require, module, global, __filename, __dirname, URL, URLSearchParams, console, process,Buffer, ...global, remoteEntryName: name}:\n {exports, require, module, global, __filename, __dirname, URL, URLSearchParams, console, process,Buffer, ...global, remoteEntryName: name};\n const remote = vm.runInNewContext(scriptContent + '\\nmodule.exports', vmContext, {filename: 'node-federation-loader-' + name + '.vm'});\n const foundContainer = remote[name] || remote\n\n if(!global.__remote_scope__[name]) {\n global.__remote_scope__[name] = foundContainer;\n global.__remote_scope__._config[name] = url;\n }\n callback(global.__remote_scope__[name]);\n } catch (e) {\n console.error('executeLoad hit catch block');\n e.target = {src: url};\n callback(e);\n }\n }).catch((e) => {\n e.target = {src: url};\n callback(e);\n });\n }\n"; |
@@ -52,3 +52,3 @@ "use strict"; | ||
if (typeof global.__remote_scope__[name] !== 'undefined') return callback(global.__remote_scope__[name]); | ||
console.log('executeLoad', url, name); | ||
const vm = require('vm'); | ||
@@ -60,6 +60,4 @@ (global.webpackChunkLoad || global.fetch || require("node-fetch"))(url).then(function (res) { | ||
// TODO: remove conditional in v7, this is to prevent breaking change between v6.0.x and v6.1.x | ||
const vmContext = typeof URLSearchParams === 'undefined' ? | ||
{exports, require, module, global, __filename, __dirname, URL, console, process,Buffer, ...global, remoteEntryName: name} : | ||
const vmContext = typeof URLSearchParams === 'undefined' ?{exports, require, module, global, __filename, __dirname, URL, URLSearchParams, console, process,Buffer, ...global, remoteEntryName: name}: | ||
{exports, require, module, global, __filename, __dirname, URL, URLSearchParams, console, process,Buffer, ...global, remoteEntryName: name}; | ||
const remote = vm.runInNewContext(scriptContent + '\\nmodule.exports', vmContext, {filename: 'node-federation-loader-' + name + '.vm'}); | ||
@@ -69,12 +67,3 @@ const foundContainer = remote[name] || remote | ||
if(!global.__remote_scope__[name]) { | ||
global.__remote_scope__[name] = { | ||
get: foundContainer.get, | ||
init: function(initScope, initToken) { | ||
try { | ||
foundContainer.init(initScope, initToken) | ||
} catch (e) { | ||
// already initialized | ||
} | ||
} | ||
}; | ||
global.__remote_scope__[name] = foundContainer; | ||
global.__remote_scope__._config[name] = url; | ||
@@ -81,0 +70,0 @@ } |
@@ -78,49 +78,3 @@ 'use strict'; | ||
} | ||
const proxy = { | ||
get: (arg)=>{ | ||
return remote.get(arg).then((f)=>{ | ||
const m = f(); | ||
return ()=>new Proxy(m, { | ||
get: (target, prop)=>{ | ||
if(global.usedChunks) global.usedChunks.add(${JSON.stringify(global)} + "->" + arg); | ||
return target[prop]; | ||
} | ||
}) | ||
}) | ||
}, | ||
init: function(shareScope) { | ||
const handler = { | ||
get(target, prop) { | ||
if (target[prop]) { | ||
Object.values(target[prop]).forEach(function(o) { | ||
if(o.from === '_N_E') { | ||
o.loaded = 1 | ||
} | ||
}) | ||
} | ||
return target[prop] | ||
}, | ||
set(target, property, value) { | ||
if(global.usedChunks) global.usedChunks.add(${JSON.stringify(global)} + "->" + property); | ||
if (target[property]) { | ||
return target[property] | ||
} | ||
target[property] = value | ||
return true | ||
} | ||
} | ||
try { | ||
global.__remote_scope__[${JSON.stringify(global)}].init(new Proxy(shareScope, handler)) | ||
} catch (e) { | ||
} | ||
global.__remote_scope__[${JSON.stringify(global)}].__initialized = true | ||
} | ||
} | ||
try { | ||
proxy.init(__webpack_require__.S.default) | ||
} catch(e) { | ||
console.error('failed to init', ${JSON.stringify(global)}, e) | ||
} | ||
return proxy | ||
return remote; | ||
})`; | ||
@@ -152,9 +106,2 @@ exports.generateRemoteTemplate = generateRemoteTemplate; | ||
const { webpack } = compiler; | ||
// const defs = { | ||
// 'process.env.REMOTES': runtime, | ||
// 'process.env.REMOTE_CONFIG': hot, | ||
// }; | ||
// new ((webpack && webpack.DefinePlugin) || require("webpack").DefinePlugin)( | ||
// defs | ||
// ).apply(compiler); | ||
const pluginOptions = { | ||
@@ -165,6 +112,20 @@ ...this._options, | ||
const chunkFileName = compiler.options?.output?.chunkFilename; | ||
if (typeof chunkFileName === 'string' && | ||
!chunkFileName.includes('[hash]') && | ||
!chunkFileName.includes('[contenthash]')) { | ||
compiler.options.output.chunkFilename = chunkFileName.replace('.js', '.[contenthash].js'); | ||
const uniqueName = compiler?.options?.output?.uniqueName || this._options.name; | ||
if (typeof chunkFileName === 'string') { | ||
const requiredSubstrings = [ | ||
'[chunkhash]', | ||
'[contenthash]', | ||
'[fullHash]', | ||
uniqueName, | ||
]; | ||
if ( | ||
//@ts-ignore | ||
!requiredSubstrings.some((substring) => | ||
//@ts-ignore | ||
chunkFileName.includes(substring))) { | ||
const suffix = compiler.options.mode === 'development' | ||
? `.[chunkhash].js` | ||
: `.[chunkhash].js`; | ||
compiler.options.output.chunkFilename = chunkFileName.replace('.js', suffix); | ||
} | ||
} | ||
@@ -171,0 +132,0 @@ new (this.context.ModuleFederationPlugin || |
@@ -0,2 +1,6 @@ | ||
/** | ||
* Initialize usedChunks and share it globally. | ||
* @type {Set} | ||
*/ | ||
export const usedChunks: Set<any>; | ||
export function flushChunks(): Promise<any[]>; |
"use strict"; | ||
/* eslint-disable no-undef */ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.flushChunks = exports.usedChunks = void 0; | ||
exports.usedChunks = new Set(); | ||
global.usedChunks = exports.usedChunks; | ||
const flushChunks = async () => { | ||
const allFlushed = await Promise.all(Array.from(exports.usedChunks).map(async (chunk) => { | ||
const chunks = new Set(); | ||
const [remote, request] = chunk.split('->'); | ||
if (!global.__remote_scope__._config[remote]) { | ||
return; | ||
if (!globalThis.usedChunks) { | ||
globalThis.usedChunks = new Set(); | ||
} | ||
/** | ||
* Initialize usedChunks and share it globally. | ||
* @type {Set} | ||
*/ | ||
exports.usedChunks = globalThis.usedChunks; | ||
/** | ||
* Load hostStats from the JSON file. | ||
* @returns {object} hostStats - An object containing host stats data. | ||
*/ | ||
const loadHostStats = () => { | ||
try { | ||
return __non_webpack_require__('../federated-stats.json'); | ||
} | ||
catch (e) { | ||
return {}; | ||
} | ||
}; | ||
/** | ||
* Create a shareMap based on the loaded modules. | ||
* @returns {object} shareMap - An object containing the shareMap data. | ||
*/ | ||
const createShareMap = () => { | ||
// Check if __webpack_share_scopes__ is defined and has a default property | ||
if (__webpack_share_scopes__?.default) { | ||
// Reduce the keys of the default property to create the share map | ||
return Object.keys(__webpack_share_scopes__.default).reduce((acc, key) => { | ||
// Get the loaded modules for the current key | ||
const loadedModules = Object.values(__webpack_share_scopes__.default[key]) | ||
// Filter out the modules that are not loaded | ||
.filter((sharedModule) => sharedModule.loaded) | ||
// Map the filtered modules to their 'from' properties | ||
.map((sharedModule) => sharedModule.from); | ||
// If there are any loaded modules, add them to the accumulator object | ||
if (loadedModules.length > 0) { | ||
acc[key] = loadedModules; | ||
} | ||
// Return the accumulator object for the next iteration | ||
return acc; | ||
}, {}); | ||
} | ||
// If __webpack_share_scopes__ is not defined or doesn't have a default property, return an empty object | ||
return {}; | ||
}; | ||
/** | ||
* Process a single chunk and return an array of updated chunks. | ||
* @param {string} chunk - A chunk string containing remote and request data. | ||
* @param {object} shareMap - An object containing the shareMap data. | ||
* @param {object} hostStats - An object containing host stats data. | ||
* @returns {Promise<Array>} A promise that resolves to an array of updated chunks. | ||
*/ | ||
const processChunk = async (chunk, shareMap, hostStats) => { | ||
// Create a set to store the chunks | ||
const chunks = new Set(); | ||
// Split the chunk string into remote and request | ||
const [remote, request] = chunk.split('->'); | ||
// If the remote is not defined in the global config, return | ||
if (!global.__remote_scope__._config[remote]) { | ||
console.error(`flush chunks:`, `Remote ${remote} is not defined in the global config`); | ||
return; | ||
} | ||
try { | ||
// Extract the remote name from the URL | ||
const remoteName = new URL(global.__remote_scope__._config[remote]).pathname | ||
.split('/') | ||
.pop(); | ||
// Construct the stats file URL from the remote config | ||
const statsFile = global.__remote_scope__._config[remote] | ||
.replace(remoteName, 'federated-stats.json') | ||
.replace('ssr', 'chunks'); | ||
let stats = {}; | ||
try { | ||
// Fetch the remote config and stats file | ||
stats = await fetch(statsFile).then((res) => res.json()); | ||
} | ||
// fetch the json file | ||
try { | ||
const statsFile = global.__remote_scope__._config[remote].replace('remoteEntry.js', 'federated-stats.json'); | ||
const stats = await fetch(statsFile).then(async (res) => await res.json()); | ||
chunks.add(global.__remote_scope__._config[remote].replace('ssr', 'chunks')); | ||
const [prefix] = global.__remote_scope__._config[remote].split('static/'); | ||
if (stats.federatedModules) { | ||
stats.federatedModules.forEach((modules) => { | ||
if (modules.exposes?.[request]) { | ||
modules.exposes[request].forEach((chunk) => { | ||
Object.values(chunk).forEach((chunk) => { | ||
chunk.forEach((chunk) => { | ||
chunks.add(prefix + chunk); | ||
catch (e) { | ||
console.error('flush error', e); | ||
} | ||
// Add the main chunk to the chunks set | ||
chunks.add(global.__remote_scope__._config[remote].replace('ssr', 'chunks')); | ||
// Extract the prefix from the remote config | ||
const [prefix] = global.__remote_scope__._config[remote].split('static/'); | ||
// Process federated modules from the stats object | ||
if (stats.federatedModules) { | ||
stats.federatedModules.forEach((modules) => { | ||
// Process exposed modules | ||
if (modules.exposes?.[request]) { | ||
modules.exposes[request].forEach((chunk) => { | ||
chunks.add([prefix, chunk].join('')); | ||
//TODO: reimplement this | ||
Object.values(chunk).forEach((chunk) => { | ||
// Add files to the chunks set | ||
if (chunk.files) { | ||
chunk.files.forEach((file) => { | ||
chunks.add(prefix + file); | ||
}); | ||
}); | ||
} | ||
// Process required modules | ||
if (chunk.requiredModules) { | ||
chunk.requiredModules.forEach((module) => { | ||
// Check if the module is in the shareMap | ||
if (shareMap[module]) { | ||
// If the module is from the host, log the host stats | ||
if (shareMap[module][0].startsWith('host__')) { | ||
console.log('host', hostStats); | ||
} | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
return Array.from(chunks); | ||
}); | ||
} | ||
}); | ||
} | ||
catch (e) { | ||
console.log(e); | ||
} | ||
})); | ||
// Return the array of chunks | ||
return Array.from(chunks); | ||
} | ||
catch (e) { | ||
console.error('flush error:', e); | ||
} | ||
}; | ||
/** | ||
* Flush the chunks and return a deduplicated array of chunks. | ||
* @returns {Promise<Array>} A promise that resolves to an array of deduplicated chunks. | ||
*/ | ||
const flushChunks = async () => { | ||
const hostStats = loadHostStats(); | ||
const shareMap = createShareMap(); | ||
const allFlushed = await Promise.all(Array.from(exports.usedChunks).map(async (chunk) => processChunk(chunk, shareMap, hostStats))); | ||
// Deduplicate the chunks array | ||
const dedupe = Array.from(new Set([...allFlushed.flat()])); | ||
// Clear usedChunks | ||
exports.usedChunks.clear(); | ||
// Filter out any undefined or null values | ||
return dedupe.filter(Boolean); | ||
@@ -41,0 +142,0 @@ }; |
@@ -22,3 +22,3 @@ "use strict"; | ||
_config: {}, | ||
_medusa: {} | ||
_medusa: {}, | ||
}; | ||
@@ -53,5 +53,9 @@ Object.keys(req.cache).forEach((key) => { | ||
for (const property in remoteScope._medusa) { | ||
fetchModule(property).then((res) => res.json()).then((medusaResponse) => { | ||
fetchModule(property) | ||
.then((res) => res.json()) | ||
.then((medusaResponse) => { | ||
//@ts-ignore | ||
if (medusaResponse.version !== remoteScope._medusa[property].version) { | ||
if (medusaResponse.version !== | ||
//@ts-ignore | ||
remoteScope?._medusa[property].version) { | ||
console.log('medusa config changed', property, 'hot reloading to refetch'); | ||
@@ -58,0 +62,0 @@ performReload(true); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
157541
1626
8
+ Addedwebpack-sources@3.2.3
+ Added@module-federation/utilities@1.8.1-rc.1(transitive)
- Removed@module-federation/utilities@1.8.0(transitive)