@module-federation/enhanced
Version:
This package provides enhanced features for module federation.
163 lines (161 loc) • 7.58 kB
JavaScript
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
const require_runtime = require('../../../_virtual/_rolldown/runtime.js');
const require_lib_sharing_tree_shaking_SharedUsedExportsOptimizerRuntimeModule = require('./SharedUsedExportsOptimizerRuntimeModule.js');
let _module_federation_sdk = require("@module-federation/sdk");
//#region src/lib/sharing/tree-shaking/SharedUsedExportsOptimizerPlugin.ts
function isHarmonyImportSpecifierDependency(dependency) {
return dependency.type === "harmony import specifier";
}
function isImportDependency(dependency) {
return dependency.type === "import()";
}
var SharedUsedExportsOptimizerPlugin = class {
constructor(sharedOptions, injectTreeShakingUsedExports, ignoredRuntime, manifestOptions) {
this.name = "SharedUsedExportsOptimizerPlugin";
this.sharedOptions = sharedOptions;
this.injectTreeShakingUsedExports = injectTreeShakingUsedExports ?? true;
this.manifestOptions = manifestOptions ?? {};
this.sharedReferencedExports = /* @__PURE__ */ new Map();
this.sharedOptions.forEach(([key, config]) => {
if (!config.treeShaking) return;
this.sharedReferencedExports.set(key, /* @__PURE__ */ new Set());
});
this.ignoredRuntime = ignoredRuntime || [];
}
applyCustomReferencedExports() {
const { sharedReferencedExports, sharedOptions } = this;
const addCustomExports = (shareKey, exports) => {
if (!sharedReferencedExports.get(shareKey)) sharedReferencedExports.set(shareKey, /* @__PURE__ */ new Set());
const sharedExports = sharedReferencedExports.get(shareKey);
exports.forEach((item) => {
sharedExports.add(item);
});
};
sharedOptions.forEach(([shareKey, config]) => {
if (config.treeShaking?.usedExports) addCustomExports(shareKey, config.treeShaking.usedExports);
});
}
apply(compiler) {
const { sharedReferencedExports, sharedOptions, injectTreeShakingUsedExports, manifestOptions } = this;
if (!sharedOptions.length) return;
compiler.hooks.compilation.tap("SharedUsedExportsOptimizerPlugin", (compilation) => {
compilation.hooks.dependencyReferencedExports.tap("SharedUsedExportsOptimizerPlugin", (referencedExports, dependency, runtime) => {
if (!("request" in dependency)) return referencedExports;
const shareKey = dependency.request;
if (typeof shareKey !== "string" || sharedOptions.every(([key]) => key !== shareKey)) return referencedExports;
let currentReferencedExports = referencedExports;
if (isImportDependency(dependency) && referencedExports === compilation.compiler.webpack.Dependency.EXPORTS_OBJECT_REFERENCED) {
sharedReferencedExports.delete(shareKey);
return currentReferencedExports;
}
if (isHarmonyImportSpecifierDependency(dependency) && dependency.ids && dependency.ids[0] === "default") {
const { ids, referencedPropertiesInDestructuring } = dependency;
const getOriginalReferencedExports = () => {
if (referencedPropertiesInDestructuring) {
/** @type {string[][]} */
const refs = [];
for (const key of referencedPropertiesInDestructuring) refs.push({
name: ids ? ids.concat([key]) : [key],
canMangle: false
});
return refs;
}
return ids ? [ids] : [[]];
};
currentReferencedExports = getOriginalReferencedExports();
}
if (!currentReferencedExports.length) return referencedExports;
currentReferencedExports.forEach((item) => {
if (typeof runtime !== "string") return;
const exportNames = [];
if (Array.isArray(item)) exportNames.push(...item);
else if (Array.isArray(item.name)) exportNames.push(...item.name);
exportNames.forEach((i) => {
const moduleExports = sharedReferencedExports.get(shareKey);
if (!moduleExports) return;
moduleExports.add(i);
});
});
return referencedExports;
});
compilation.hooks.optimizeDependencies.tap({
name: "SharedUsedExportsOptimizerPlugin",
stage: 1
}, (modules) => {
this.applyCustomReferencedExports();
const sharedModules = [...modules].filter((m) => [
"consume-shared-module",
"provide-module",
"shared-entry-module"
].includes(m.type));
const moduleGraph = compilation.moduleGraph;
sharedModules.forEach((module) => {
const shareKey = module.options?.shareKey || module._name || module._name;
if (!shareKey) return;
if (!sharedOptions.find(([key]) => key === shareKey)?.[1].treeShaking) return;
const referenceExports = sharedReferencedExports.get(shareKey);
if (!referenceExports || !referenceExports.size) return;
const realSharedModule = [...modules].find((m) => "rawRequest" in m && m.rawRequest === shareKey);
if (realSharedModule?.factoryMeta?.sideEffectFree !== true) {
referenceExports.clear();
return;
}
const handleDependency = (dep) => {
const usedExport = [...referenceExports];
const referencedModule = moduleGraph.getModule(dep);
if (!referencedModule) return;
const exportsInfo = moduleGraph.getExportsInfo(referencedModule);
for (let i = 0; i < usedExport.length; i++) exportsInfo.getExportInfo(usedExport[i]).setUsed(compiler.webpack.UsageState.Used, void 0);
};
module.blocks.forEach((block) => {
block.dependencies.forEach((dep) => {
handleDependency(dep);
});
});
module.dependencies.forEach((dep) => {
handleDependency(dep);
});
module.factoryMeta ||= {};
module.factoryMeta.sideEffectFree = true;
if (!realSharedModule) return;
const exportsInfo = compilation.moduleGraph.getExportsInfo(realSharedModule);
let canUpdateModuleUsedStage = true;
for (const subExport of exportsInfo.exports) {
const used = subExport.getUsed(void 0);
if (used !== 3 && used !== 0) {
if (referenceExports.has(subExport.name)) continue;
canUpdateModuleUsedStage = false;
break;
}
}
if (canUpdateModuleUsedStage) for (const exportInfo of exportsInfo.exports) exportInfo.setUsedConditionally((used) => used === 3, 0, void 0);
});
});
if (manifestOptions) compilation.hooks.processAssets.tapPromise({
name: "injectReferenceExports",
stage: compilation.constructor.PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER
}, async () => {
const { statsFileName } = (0, _module_federation_sdk.getManifestFileName)(manifestOptions);
const stats = compilation.getAsset(statsFileName);
if (!stats) return;
const statsContent = JSON.parse(stats.source.source().toString());
for (const key of sharedReferencedExports.keys()) {
const sharedModule = statsContent.shared.find((s) => s.name === key);
if (!sharedModule) continue;
const sharedReferenceExports = sharedReferencedExports.get(key);
if (!sharedReferenceExports) continue;
sharedModule.usedExports = [...sharedReferenceExports];
}
compilation.updateAsset(statsFileName, new compiler.webpack.sources.RawSource(JSON.stringify(statsContent, null, 2)));
});
if (!injectTreeShakingUsedExports) return;
compilation.hooks.additionalTreeRuntimeRequirements.tap("SharedUsedExportsOptimizerPlugin", (chunk, set) => {
set.add(compiler.webpack.RuntimeGlobals.runtimeId);
compilation.addRuntimeModule(chunk, new require_lib_sharing_tree_shaking_SharedUsedExportsOptimizerRuntimeModule.default(this.sharedReferencedExports));
});
});
}
};
//#endregion
exports.default = SharedUsedExportsOptimizerPlugin;
//# sourceMappingURL=SharedUsedExportsOptimizerPlugin.js.map