UNPKG

@module-federation/manifest

Version:

Provide manifest/stats for webpack/rspack MF project .

536 lines (524 loc) • 23.6 kB
"use strict"; const __rslib_import_meta_url__ = /*#__PURE__*/ (function () { return typeof document === 'undefined' ? new (require('url'.replace('', '')).URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src) || new URL('main.js', document.baseURI).href; })(); ; // The require scope var __webpack_require__ = {}; /************************************************************************/ // webpack/runtime/compat_get_default_export (() => { // getDefaultExport function for compatibility with non-ESM modules __webpack_require__.n = (module) => { var getter = module && module.__esModule ? () => (module['default']) : () => (module); __webpack_require__.d(getter, { a: getter }); return getter; }; })(); // webpack/runtime/define_property_getters (() => { __webpack_require__.d = (exports, definition) => { for(var key in definition) { if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); } } }; })(); // webpack/runtime/has_own_property (() => { __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) })(); // webpack/runtime/make_namespace_object (() => { // define __esModule on exports __webpack_require__.r = (exports) => { if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); } Object.defineProperty(exports, '__esModule', { value: true }); }; })(); /************************************************************************/ var __webpack_exports__ = {}; // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { StatsManager: () => (/* binding */ StatsManager) }); ;// CONCATENATED MODULE: external "@module-federation/sdk" const sdk_namespaceObject = require("@module-federation/sdk"); ;// CONCATENATED MODULE: external "./utils.js" const external_utils_js_namespaceObject = require("./utils.js"); ;// CONCATENATED MODULE: external "./logger.js" const external_logger_js_namespaceObject = require("./logger.js"); var external_logger_js_default = /*#__PURE__*/__webpack_require__.n(external_logger_js_namespaceObject); ;// CONCATENATED MODULE: external "@module-federation/managers" const managers_namespaceObject = require("@module-federation/managers"); ;// CONCATENATED MODULE: external "./constants.js" const external_constants_js_namespaceObject = require("./constants.js"); ;// CONCATENATED MODULE: external "./ModuleHandler.js" const external_ModuleHandler_js_namespaceObject = require("./ModuleHandler.js"); ;// CONCATENATED MODULE: ./src/StatsManager.ts /* eslint-disable max-lines-per-function */ /* eslint-disable @typescript-eslint/member-ordering */ /* eslint-disable max-depth */ class StatsManager { getBuildInfo(context, target) { const rootPath = context || process.cwd(); const pkg = this._pkgJsonManager.readPKGJson(rootPath); const statsBuildInfo = { buildVersion: managers_namespaceObject.utils.getBuildVersion(rootPath), buildName: managers_namespaceObject.utils.getBuildName() || pkg['name'] }; if (this._sharedManager.enableTreeShaking) { statsBuildInfo.target = target ? Array.isArray(target) ? target : [ target ] : []; statsBuildInfo.plugins = this._options.treeShakingSharedPlugins || []; statsBuildInfo.excludePlugins = this._options.treeShakingSharedExcludePlugins || []; } return statsBuildInfo; } get fileName() { return (0,sdk_namespaceObject.getManifestFileName)(this._options.manifest).statsFileName; } setMetaDataPublicPath(metaData, compiler) { if (this._options.getPublicPath) { if ('publicPath' in metaData) { // @ts-ignore delete metaData.publicPath; } metaData.getPublicPath = this._options.getPublicPath; } else { metaData.publicPath = this.getPublicPath(compiler); } return metaData; } _getMetaData(compiler, compilation, extraOptions) { var _this__options_library, _this__options; const { context } = compiler.options; const { _options: { name } } = this; const buildInfo = this.getBuildInfo(context, compilation.options.target || ''); const type = this._pkgJsonManager.getExposeGarfishModuleType(context || process.cwd()); const getRemoteEntryName = ()=>{ if (!this._containerManager.enable) { return ''; } (0,external_utils_js_namespaceObject.assert)(name, 'name is required'); const remoteEntryPoint = compilation.entrypoints.get(name); (0,external_utils_js_namespaceObject.assert)(remoteEntryPoint, 'Can not get remoteEntry entryPoint!'); const remoteEntryNameChunk = compilation.namedChunks.get(name); (0,external_utils_js_namespaceObject.assert)(remoteEntryNameChunk, 'Can not get remoteEntry chunk!'); const files = Array.from(remoteEntryNameChunk.files).filter((f)=>!f.includes(external_constants_js_namespaceObject.HOT_UPDATE_SUFFIX) && !f.endsWith('.css')); (0,external_utils_js_namespaceObject.assert)(files.length > 0, 'no files found for remoteEntry chunk'); (0,external_utils_js_namespaceObject.assert)(files.length === 1, `remoteEntry chunk should not have multiple files!, current files: ${files.join(',')}`); const remoteEntryName = files[0]; return remoteEntryName; }; const globalName = this._containerManager.globalEntryName; (0,external_utils_js_namespaceObject.assert)(globalName, 'Can not get library.name, please ensure you have set library.name and the type is "string" !'); (0,external_utils_js_namespaceObject.assert)(this._pluginVersion, 'Can not get pluginVersion, please ensure you have set pluginVersion !'); const metaData = { name: name, type, buildInfo, remoteEntry: { name: getRemoteEntryName(), path: '', // same as the types supported by runtime, currently only global/var/script is supported type: ((_this__options = this._options) === null || _this__options === void 0 ? void 0 : (_this__options_library = _this__options.library) === null || _this__options_library === void 0 ? void 0 : _this__options_library.type) || 'global' }, types: (0,external_utils_js_namespaceObject.getTypesMetaInfo)(this._options, compiler.context), globalName: globalName, pluginVersion: this._pluginVersion }; return this.setMetaDataPublicPath(metaData, compiler); } _getFilteredModules(stats) { const filteredModules = stats.modules.filter((module)=>{ if (!module || !module.name) { return false; } const array = [ module.name.includes('container entry'), module.name.includes('remote '), module.name.includes('shared module '), module.name.includes('provide module ') ]; return array.some((item)=>item); }); return filteredModules; } _getModuleAssets(compilation, entryPointNames) { const { chunks } = compilation; const { exposeFileNameImportMap } = this._containerManager; const assets = {}; chunks.forEach((chunk)=>{ if (typeof chunk.name !== 'string') return; // Support split chunks caused by splitChunks.maxSize: // A chunk named "__federation_expose_Foo" may be split into // "__federation_expose_Foo-<hash>" chunks, so we match both exact // and prefix+dash patterns. const matchedKey = exposeFileNameImportMap[chunk.name] !== undefined ? chunk.name : Object.keys(exposeFileNameImportMap).find((key)=>chunk.name.startsWith(key + '-')); if (!matchedKey) return; // TODO: support multiple import const exposeKey = exposeFileNameImportMap[matchedKey][0]; const assetKey = (0,external_utils_js_namespaceObject.getFileNameWithOutExt)(exposeKey); const chunkAssets = (0,external_utils_js_namespaceObject.getAssetsByChunk)(chunk, entryPointNames); if (!assets[assetKey]) { assets[assetKey] = chunkAssets; } else { // Merge split chunk assets, deduplicating with Set assets[assetKey] = { js: { sync: [ ...new Set([ ...assets[assetKey].js.sync, ...chunkAssets.js.sync ]) ], async: [ ...new Set([ ...assets[assetKey].js.async, ...chunkAssets.js.async ]) ] }, css: { sync: [ ...new Set([ ...assets[assetKey].css.sync, ...chunkAssets.css.sync ]) ], async: [ ...new Set([ ...assets[assetKey].css.async, ...chunkAssets.css.async ]) ] } }; } }); return assets; } _getProvideSharedAssets(compilation, stats, entryPointNames) { const sharedModules = stats.modules.filter((module)=>{ if (!module || !module.name) { return false; } const array = [ module.name.includes('consume shared module ') ]; return array.some((item)=>item); }); const manifestOverrideChunkIDMap = {}; const effectiveSharedModules = (0,external_utils_js_namespaceObject.getSharedModules)(stats, sharedModules); effectiveSharedModules.forEach((item)=>{ const [sharedModuleName, sharedModule] = item; if (!manifestOverrideChunkIDMap[sharedModuleName]) { manifestOverrideChunkIDMap[sharedModuleName] = { async: new Set(), sync: new Set() }; } sharedModule.chunks.forEach((chunkID)=>{ const chunk = (0,external_utils_js_namespaceObject.findChunk)(chunkID, compilation.chunks); manifestOverrideChunkIDMap[sharedModuleName].sync.add(chunkID); if (!chunk) { return; } [ ...chunk.groupsIterable ].forEach((group)=>{ if (group.name && !entryPointNames.includes(group.name)) { manifestOverrideChunkIDMap[sharedModuleName].sync.add(group.id); } }); }); }); const assets = { js: { async: [], sync: [] }, css: { async: [], sync: [] } }; Object.keys(manifestOverrideChunkIDMap).forEach((override)=>{ const asyncAssets = (0,external_utils_js_namespaceObject.getAssetsByChunkIDs)(compilation, { [override]: manifestOverrideChunkIDMap[override].async }); const syncAssets = (0,external_utils_js_namespaceObject.getAssetsByChunkIDs)(compilation, { [override]: manifestOverrideChunkIDMap[override].sync }); assets[override] = { js: { async: asyncAssets[override].js, sync: syncAssets[override].js }, css: { async: asyncAssets[override].css, sync: syncAssets[override].css } }; }); return assets; } async _generateStats(compiler, compilation, extraOptions) { try { const { name, manifest: manifestOptions = {}, exposes = {} } = this._options; const metaData = this._getMetaData(compiler, compilation, extraOptions); const stats = { id: name, name: name, metaData, shared: [], remotes: [], exposes: [] }; if (typeof manifestOptions === 'object' && manifestOptions.disableAssetsAnalyze) { const remotes = this._remoteManager.statsRemoteWithEmptyUsedIn; stats.remotes = remotes; stats.exposes = Object.keys(exposes).map((exposeKey)=>{ return (0,external_ModuleHandler_js_namespaceObject.getExposeItem)({ exposeKey, name: name, file: { import: exposes[exposeKey].import } }); }); stats.shared = Object.entries(this._sharedManager.normalizedOptions).reduce((sum, cur)=>{ const [pkgName, normalizedShareOptions] = cur; sum.push((0,external_ModuleHandler_js_namespaceObject.getShareItem)({ pkgName, normalizedShareOptions, pkgVersion: normalizedShareOptions.version || managers_namespaceObject.UNKNOWN_MODULE_NAME, hostName: name })); return sum; }, []); return stats; } const liveStats = compilation.getStats(); const statsOptions = { all: false, modules: true, builtAt: true, hash: true, ids: true, version: true, entrypoints: true, assets: false, chunks: false, reasons: true }; if (this._bundler === 'webpack') { statsOptions['cached'] = true; } statsOptions['cachedModules'] = true; const webpackStats = liveStats.toJson(statsOptions); const filteredModules = this._getFilteredModules(webpackStats); const moduleHandler = new external_ModuleHandler_js_namespaceObject.ModuleHandler(this._options, filteredModules, { bundler: this._bundler }); const { remotes, exposesMap, sharedMap } = moduleHandler.collect(); const entryPointNames = [ ...compilation.entrypoints.values() ].map((e)=>e.name).filter((v)=>!!v); await Promise.all([ new Promise((resolve)=>{ const sharedAssets = this._getProvideSharedAssets(compilation, webpackStats, entryPointNames); Object.keys(sharedMap).forEach((sharedKey)=>{ const assets = sharedAssets[sharedKey]; if (assets) { sharedMap[sharedKey].assets = assets; } }); resolve(); }), new Promise((resolve)=>{ const moduleAssets = this._getModuleAssets(compilation, entryPointNames); Object.keys(exposesMap).forEach((exposeKey)=>{ const assets = moduleAssets[exposeKey]; if (assets) { exposesMap[exposeKey].assets = assets; } exposesMap[exposeKey].requires = Array.from(new Set(exposesMap[exposeKey].requires)); }); resolve(); }) ]); await Promise.all([ new Promise((resolve)=>{ const remoteMemo = new Set(); stats.remotes = remotes.map((remote)=>{ remoteMemo.add(remote.federationContainerName); return { ...remote, usedIn: Array.from(remote.usedIn.values()) }; }); const statsRemoteWithEmptyUsedIn = this._remoteManager.statsRemoteWithEmptyUsedIn; statsRemoteWithEmptyUsedIn.forEach((remoteInfo)=>{ if (!remoteMemo.has(remoteInfo.federationContainerName)) { stats.remotes.push(remoteInfo); } }); resolve(); }), new Promise((resolve)=>{ stats.shared = Object.values(sharedMap).map((shared)=>({ ...shared, usedIn: Array.from(shared.usedIn) })); resolve(); }) ]); await new Promise((resolve)=>{ const sharedAssets = stats.shared.reduce((sum, shared)=>{ const { js, css } = shared.assets; [ ...js.sync, ...js.async, ...css.async, css.sync ].forEach((asset)=>{ sum.add(asset); }); return sum; }, new Set()); const { fileExposeKeyMap } = this._containerManager; stats.exposes = []; Object.entries(fileExposeKeyMap).forEach(([exposeFileWithoutExt, exposeKeySet])=>{ const expose = exposesMap[exposeFileWithoutExt] || { assets: { js: { sync: [], async: [] }, css: { sync: [], async: [] } } }; exposeKeySet.forEach((exposeKey)=>{ const { js, css } = expose.assets; const exposeModuleName = (0,external_ModuleHandler_js_namespaceObject.getExposeName)(exposeKey); stats.exposes.push({ ...expose, path: exposeKey, id: (0,sdk_namespaceObject.composeKeyWithSeparator)(this._options.name, exposeModuleName), name: exposeModuleName, assets: { js: { sync: js.sync.filter((asset)=>!sharedAssets.has(asset)), async: js.async.filter((asset)=>!sharedAssets.has(asset)) }, css: { sync: css.sync.filter((asset)=>!sharedAssets.has(asset)), async: css.async.filter((asset)=>!sharedAssets.has(asset)) } } }); }); }); Object.values(exposesMap).map((expose)=>{ const { js, css } = expose.assets; return { ...expose, assets: { js: { sync: js.sync.filter((asset)=>!sharedAssets.has(asset)), async: js.async.filter((asset)=>!sharedAssets.has(asset)) }, css: { sync: css.sync.filter((asset)=>!sharedAssets.has(asset)), async: css.async.filter((asset)=>!sharedAssets.has(asset)) } } }; }); resolve(); }); return stats; } catch (err) { throw err; } } getPublicPath(compiler) { if (this._publicPath) { return this._publicPath; } const { output: { publicPath: originalPublicPath } } = compiler.options; let publicPath = originalPublicPath; this._publicPath = publicPath; return publicPath; } init(options, { pluginVersion, bundler }) { this._options = options; this._pluginVersion = pluginVersion; this._bundler = bundler; this._containerManager = new managers_namespaceObject.ContainerManager(); this._containerManager.init(options); this._remoteManager = new managers_namespaceObject.RemoteManager(); this._remoteManager.init(options); this._sharedManager = new managers_namespaceObject.SharedManager(); this._sharedManager.init(options); } updateStats(stats, compiler) { const { metaData } = stats; if (!metaData.types) { metaData.types = (0,external_utils_js_namespaceObject.getTypesMetaInfo)(this._options, compiler.context); } if (!metaData.pluginVersion) { metaData.pluginVersion = this._pluginVersion; } this.setMetaDataPublicPath(metaData, compiler); return stats; } async generateStats(compiler, compilation) { try { const stats = await this._generateStats(compiler, compilation); return stats; } catch (err) { throw err; } } validate(compiler) { const { output: { publicPath } } = compiler.options; if (typeof publicPath !== 'string') { external_logger_js_default().warn(`Manifest will not generate, because publicPath can only be string, but got '${publicPath}'`); return false; } else if (publicPath === 'auto') { external_logger_js_default().warn(`Manifest will use absolute path resolution via its host at runtime, reason: publicPath='${publicPath}'`); return true; } return true; } constructor(){ this._options = {}; this._bundler = 'webpack'; this._containerManager = new managers_namespaceObject.ContainerManager(); this._remoteManager = new managers_namespaceObject.RemoteManager(); this._sharedManager = new managers_namespaceObject.SharedManager(); this._pkgJsonManager = new managers_namespaceObject.PKGJsonManager(); } } exports.StatsManager = __webpack_exports__.StatsManager; for(var __webpack_i__ in __webpack_exports__) { if(["StatsManager"].indexOf(__webpack_i__) === -1) { exports[__webpack_i__] = __webpack_exports__[__webpack_i__]; } } Object.defineProperty(exports, '__esModule', { value: true });