Project Init

This commit is contained in:
Muluhabt
2026-05-29 15:23:46 +03:00
commit 2fbc557aac
67387 changed files with 6063341 additions and 0 deletions

View File

@@ -0,0 +1,324 @@
import { bindLoggerToCompiler, composeKeyWithSeparator } from "@module-federation/sdk";
import { StatsPlugin } from "@module-federation/manifest";
import { ContainerManager, utils } from "@module-federation/managers";
import { DtsPlugin } from "@module-federation/dts-plugin";
import bridge_react_webpack_plugin from "@module-federation/bridge-react-webpack-plugin";
import node_path from "node:path";
import node_fs from "node:fs";
import { RemoteEntryPlugin } from "./RemoteEntryPlugin.mjs";
import logger from "./logger.mjs";
import { TreeShakingSharedPlugin } from "./TreeShakingSharedPlugin.mjs";
;// CONCATENATED MODULE: external "@module-federation/sdk"
;// CONCATENATED MODULE: external "@module-federation/manifest"
;// CONCATENATED MODULE: external "@module-federation/managers"
;// CONCATENATED MODULE: external "@module-federation/dts-plugin"
;// CONCATENATED MODULE: external "@module-federation/bridge-react-webpack-plugin"
;// CONCATENATED MODULE: external "node:path"
;// CONCATENATED MODULE: external "node:fs"
;// CONCATENATED MODULE: external "./RemoteEntryPlugin.mjs"
;// CONCATENATED MODULE: external "./logger.mjs"
;// CONCATENATED MODULE: external "./TreeShakingSharedPlugin.mjs"
;// CONCATENATED MODULE: ./src/ModuleFederationPlugin.ts
const PLUGIN_NAME = 'RspackModuleFederationPlugin';
function resolveRuntimeEntry(spec, implementation, resolve = require.resolve) {
const candidates = [
spec.bundler,
spec.esm,
spec.cjs
];
const modulePaths = implementation ? [
implementation
] : undefined;
let lastError;
for (const candidate of candidates){
try {
return modulePaths ? resolve(candidate, {
paths: modulePaths
}) : resolve(candidate);
} catch (error) {
lastError = error;
}
}
throw lastError;
}
function resolveRspackRuntimeImplementation(implementation, resolve = require.resolve) {
return resolveRuntimeEntry({
bundler: '@module-federation/runtime-tools/bundler',
esm: '@module-federation/runtime-tools/dist/index.js',
cjs: '@module-federation/runtime-tools/dist/index.cjs'
}, implementation, resolve);
}
function resolveRspackRuntimeAlias(implementation, resolve = require.resolve) {
return resolveRuntimeEntry({
bundler: '@module-federation/runtime/bundler',
esm: '@module-federation/runtime/dist/index.js',
cjs: '@module-federation/runtime/dist/index.cjs'
}, implementation, resolve);
}
class ModuleFederationPlugin {
_patchBundlerConfig(compiler) {
var _experiments_optimization;
const { name, experiments } = this._options;
const definePluginOptions = {};
if (name) {
definePluginOptions['FEDERATION_BUILD_IDENTIFIER'] = JSON.stringify(composeKeyWithSeparator(name, utils.getBuildVersion()));
}
// Add FEDERATION_OPTIMIZE_NO_SNAPSHOT_PLUGIN
const disableSnapshot = (experiments === null || experiments === void 0 ? void 0 : (_experiments_optimization = experiments.optimization) === null || _experiments_optimization === void 0 ? void 0 : _experiments_optimization.disableSnapshot) ?? false;
definePluginOptions['FEDERATION_OPTIMIZE_NO_SNAPSHOT_PLUGIN'] = disableSnapshot;
// Determine ENV_TARGET: only if manually specified in experiments.optimization.target
if ((experiments === null || experiments === void 0 ? void 0 : experiments.optimization) && typeof experiments.optimization === 'object' && experiments.optimization !== null && 'target' in experiments.optimization) {
const manualTarget = experiments.optimization.target;
// Ensure the target is one of the expected values before setting
if (manualTarget === 'web' || manualTarget === 'node') {
definePluginOptions['ENV_TARGET'] = JSON.stringify(manualTarget);
}
}
// No inference for ENV_TARGET. If not manually set and valid, it's not defined.
new compiler.webpack.DefinePlugin(definePluginOptions).apply(compiler);
}
_checkSingleton(compiler) {
let count = 0;
compiler.options.plugins.forEach((p)=>{
if (typeof p !== 'object' || !p) {
return;
}
if (p['name'] === this.name) {
count++;
if (count > 1) {
throw new Error(`Detect duplicate register ${this.name},please ensure ${this.name} is singleton!`);
}
}
});
}
apply(compiler) {
var _options_experiments, _options_experiments1;
bindLoggerToCompiler(logger, compiler, PLUGIN_NAME);
const { _options: options } = this;
if (!options.name) {
throw new Error('[ ModuleFederationPlugin ]: name is required');
}
this._checkSingleton(compiler);
this._patchBundlerConfig(compiler);
const containerManager = new ContainerManager();
containerManager.init(options);
if (containerManager.enable) {
this._patchChunkSplit(compiler, options.name);
}
// must before ModuleFederationPlugin
new RemoteEntryPlugin(options).apply(compiler);
if ((_options_experiments = options.experiments) === null || _options_experiments === void 0 ? void 0 : _options_experiments.provideExternalRuntime) {
if (containerManager.enable) {
throw new Error('You can only set provideExternalRuntime: true in pure consumer which not expose modules.');
}
const runtimePlugins = options.runtimePlugins || [];
options.runtimePlugins = runtimePlugins.concat(require.resolve('@module-federation/inject-external-runtime-core-plugin'));
}
if (((_options_experiments1 = options.experiments) === null || _options_experiments1 === void 0 ? void 0 : _options_experiments1.externalRuntime) === true) {
const Externals = compiler.webpack.ExternalsPlugin;
new Externals(compiler.options.externalsType || 'global', {
'@module-federation/runtime-core': '_FEDERATION_RUNTIME_CORE'
}).apply(compiler);
}
const implementationPath = options.implementation ? options.implementation : resolveRspackRuntimeImplementation();
options.implementation = implementationPath;
let disableManifest = options.manifest === false;
let disableDts = options.dts === false;
if (!disableDts) {
const dtsPlugin = new DtsPlugin(options);
// @ts-ignore
dtsPlugin.apply(compiler);
dtsPlugin.addRuntimePlugins();
}
if (!disableManifest && options.exposes) {
try {
options.exposes = containerManager.containerPluginExposesOptions;
} catch (err) {
if (err instanceof Error) {
err.message = `[ ModuleFederationPlugin ]: Manifest will not generate, because: ${err.message}`;
}
logger.warn(err);
disableManifest = true;
}
}
new compiler.webpack.container.ModuleFederationPlugin(options).apply(compiler);
let runtimePath;
try {
runtimePath = resolveRspackRuntimeAlias(implementationPath);
} catch (err) {
const detail = err instanceof Error ? err.message : String(err);
throw new Error(`[ ModuleFederationPlugin ]: Unable to resolve runtime entry (paths: [${implementationPath}]): ${detail}`);
}
compiler.hooks.afterPlugins.tap('PatchAliasWebpackPlugin', ()=>{
compiler.options.resolve.alias = {
...compiler.options.resolve.alias,
'@module-federation/runtime$': runtimePath
};
});
if (!disableManifest) {
this._statsPlugin = new StatsPlugin(options, {
pluginVersion: "2.5.0",
bundler: 'rspack'
});
// @ts-ignore
this._statsPlugin.apply(compiler);
}
const checkBridgeReactInstalled = ()=>{
try {
const userPackageJsonPath = node_path.resolve(compiler.context, 'package.json');
if (node_fs.existsSync(userPackageJsonPath)) {
const userPackageJson = JSON.parse(node_fs.readFileSync(userPackageJsonPath, 'utf-8'));
const userDependencies = {
...userPackageJson.dependencies,
...userPackageJson.devDependencies
};
return !!userDependencies['@module-federation/bridge-react'];
}
return false;
} catch (error) {
return false;
}
};
const hasBridgeReact = checkBridgeReactInstalled();
// react bridge plugin
const shouldEnableBridgePlugin = ()=>{
var _options_bridge, _options_bridge1, _options_bridge2;
// Priority 1: Explicit enableBridgeRouter configuration
if ((options === null || options === void 0 ? void 0 : (_options_bridge = options.bridge) === null || _options_bridge === void 0 ? void 0 : _options_bridge.enableBridgeRouter) === true) {
return true;
}
// Priority 2: Explicit disable via enableBridgeRouter:false or disableAlias:true
if ((options === null || options === void 0 ? void 0 : (_options_bridge1 = options.bridge) === null || _options_bridge1 === void 0 ? void 0 : _options_bridge1.enableBridgeRouter) === false || (options === null || options === void 0 ? void 0 : (_options_bridge2 = options.bridge) === null || _options_bridge2 === void 0 ? void 0 : _options_bridge2.disableAlias) === true) {
var _options_bridge3;
if ((options === null || options === void 0 ? void 0 : (_options_bridge3 = options.bridge) === null || _options_bridge3 === void 0 ? void 0 : _options_bridge3.disableAlias) === true) {
logger.warn("\u26A0\uFE0F [ModuleFederationPlugin] The `disableAlias` option is deprecated and will be removed in a future version.\n" + ' Please use `enableBridgeRouter: false` instead:\n' + ' {\n' + ' bridge: {\n' + ' enableBridgeRouter: false // Use this instead of disableAlias: true\n' + ' }\n' + ' }');
}
return false;
}
// Priority 3: Automatic detection based on bridge-react installation
if (hasBridgeReact) {
logger.info("\uD83D\uDCA1 [ModuleFederationPlugin] Detected @module-federation/bridge-react in your dependencies.\n" + ' For better control and to avoid future breaking changes, please explicitly set:\n' + ' {\n' + ' bridge: {\n' + ' enableBridgeRouter: true // Explicitly enable bridge router\n' + ' }\n' + ' }');
return true;
}
return false;
};
const enableBridgePlugin = shouldEnableBridgePlugin();
// When bridge plugin is disabled (router disabled), alias to /base entry
if (!enableBridgePlugin && hasBridgeReact) {
compiler.hooks.afterPlugins.tap('BridgeReactBaseAliasPlugin', ()=>{
try {
const bridgeReactBasePath = node_path.resolve(compiler.context, 'node_modules/@module-federation/bridge-react/dist/base.es.js');
if (!node_fs.existsSync(bridgeReactBasePath)) {
logger.warn("\u26A0\uFE0F [ModuleFederationPlugin] bridge-react /base entry not found, falling back to default entry");
return;
}
compiler.options.resolve.alias = {
...compiler.options.resolve.alias,
'@module-federation/bridge-react$': bridgeReactBasePath
};
logger.info("\u2705 [ModuleFederationPlugin] Router disabled - using /base entry (no react-router-dom)");
} catch (error) {
logger.warn("\u26A0\uFE0F [ModuleFederationPlugin] Failed to set /base alias, using default entry");
}
});
}
if (enableBridgePlugin) {
new bridge_react_webpack_plugin({
moduleFederationOptions: this._options
}).apply(compiler);
}
}
_patchChunkSplit(compiler, name) {
const { splitChunks } = compiler.options.optimization;
const patchChunkSplit = (cacheGroup)=>{
switch(typeof cacheGroup){
case 'boolean':
case 'string':
case 'function':
break;
// cacheGroup.chunks will inherit splitChunks.chunks, so you only need to modify the chunks that are set separately
case 'object':
{
if (cacheGroup instanceof RegExp) {
break;
}
if (!cacheGroup.chunks) {
break;
}
if (typeof cacheGroup.chunks === 'function') {
const prevChunks = cacheGroup.chunks;
cacheGroup.chunks = (chunk)=>{
if (chunk.name && (chunk.name === name || chunk.name === name + '_partial')) {
return false;
}
return prevChunks(chunk);
};
break;
}
if (cacheGroup.chunks === 'all') {
cacheGroup.chunks = (chunk)=>{
if (chunk.name && (chunk.name === name || chunk.name === name + '_partial')) {
return false;
}
return true;
};
break;
}
if (cacheGroup.chunks === 'initial') {
cacheGroup.chunks = (chunk)=>{
if (chunk.name && (chunk.name === name || chunk.name === name + '_partial')) {
return false;
}
return chunk.isOnlyInitial();
};
break;
}
break;
}
default:
break;
}
};
if (!splitChunks) {
return;
}
// 修改 splitChunk.chunks
patchChunkSplit(splitChunks);
const { cacheGroups } = splitChunks;
if (!cacheGroups) {
return;
}
// 修改 splitChunk.cacheGroups[key].chunks
Object.keys(cacheGroups).forEach((cacheGroupKey)=>{
patchChunkSplit(cacheGroups[cacheGroupKey]);
});
}
constructor(options){
this.name = PLUGIN_NAME;
this._options = options;
}
}
const GetPublicPathPlugin = RemoteEntryPlugin;
export { GetPublicPathPlugin, ModuleFederationPlugin, PLUGIN_NAME, TreeShakingSharedPlugin, resolveRspackRuntimeAlias, resolveRspackRuntimeImplementation };