import {registerRemotes, loadRemote} from "@module-federation/runtime";
function loadComponent(scope, module) {
return async () => {
if(!scope && !module) {
return {default: ()=>null}
}
return await loadRemote(scope + module.replace('.',''));
};
}
getPublicPath
使用 getPublicPath 动态设置租户模块资源前缀
- 用于设置动态 publicPath,设置后,对应的远程模块资源也将使用此 publicPath。例如,部署的项目是动态下发
cdn_prefix
,那么可以设置getPublicPath
为return "https:" + window.navigator.cdn_host + "/resource/app/"
- 设置了 getPublicPath,在其他消费者加载该生产者时,将会通过 new Function 的方式执行 getPublicPath 的代码获取到返回值,将会把返回值的内容作为该模块的 publicPath 静态资源前缀
module.exports = {
plugins: [
new ModuleFederation({
name: 'provider',
exposes: {
'./Button': './src/components/Button.tsx',
},
// ...
getPublicPath: `return "https:" + window.navigator.cdn_host + "/resource/app/"`,
}),
],
};
externalRuntime
- Type:
boolean
- Required: No
- Default:
false
设置 true
后 会 external MF runtime,并使用消费者提供的 runtime 。(请确保你的消费者有设置 provideExternalRuntime: true
,否则无法正常运行!)
使用 CDN
app1 = host
/* NpmRuntimePlugin 用于模块联邦
* --------------------------------------
* 此插件通过修改共享模块的解析方式扩展了模块联邦运行时的功能。
*
* 功能:
* 1. 插件挂钩到联邦运行时的 'resolveShare' 钩子。
* 2. 它更新共享模块工厂的引用,允许它们指向外部资源(如 unpkg 或 esm.sh)。
* 3. 这对于某些包(如 'lodash')更倾向于从这些外部资源加载而不是打包时特别有用。
*
* 工作原理:
* - 插件定义了一个 'useLocalShares' 集合,指定哪些模块应使用本地解析。
* - 'getShareFromUnpkg' 函数根据包名和版本动态导入来自 esm.sh 的模块。
* - 在 'resolveShare' 钩子中,插件检查包是否应使用本地解析(基于 'useLocalShares')。
* - 如果不是,它会更新包引用以从外部资源获取。
* - 'beforeLoadShare' 钩子包含一个旧问题的解决方法,该问题可能已不再相关。
*
* 用法:
* - 使用 'registerGlobalPlugins' 注册插件,以在模块联邦上下文中启用其功能。
*
* 注意:
* - 此插件提供了一种灵活的方式来控制模块解析,优化包大小,并在需要时利用 CDN 托管的模块。
*/
import { registerGlobalPlugins } from '@module-federation/runtime';
const useLocalShares = new Set(['lodash']);
//workaround for rspack who cannot process webpackIgnore comments yet
const getShareFromUnpkg = (packageName, version) => {
return () => {
const mod = new Function(
'packageName',
'version',
'return import(/* webpackIgnore: true */ `https://esm.sh/${packageName}@${version}`)',
)(packageName, version);
return mod.then(m => {
return () => m;
});
};
};
const store = {};
const NpmRuntimeGlobalPlugin = () => {
return {
name: 'share-from-npm-plugin',
beforeInit: args => {
store.name = args.options.name;
return args;
},
resolveShare: args => {
const { shareScopeMap, scope, pkgName, version, resolver } = args;
const currentPackageRef = shareScopeMap[scope][pkgName][version];
args.resolver = () => {
if (!useLocalShares.has(pkgName)) {
currentPackageRef.get = getShareFromUnpkg(pkgName, version);
}
return resolver();
};
return args;
},
beforeLoadShare: async args => {
// old workaround, may not be required anymore
while (__FEDERATION__.__INSTANCES__.length <= 1) {
await new Promise(r => setTimeout(r, 50));
}
return args;
},
};
};
registerGlobalPlugins([NpmRuntimeGlobalPlugin()]);
export default () => ({
name: 'empty-plugin',
});
app2
new ModuleFederationPlugin({
name: 'app2',
library: { type: 'var', name: 'app2' },
filename: 'remoteEntry.js',
runtimePlugins: [
// uses global plugin injected by app1
// 使用全局运行时插件
],
exposes: {
'./Button': './src/Button',
},
shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
}),
new HtmlWebpackPlugin({
template: './public/index.html',
}),
offline-remote
export default function () {
const getErrorMessage = (id, error) => `remote ${id} is offline due to error: ${error}`;
const getModule = (pg, from) => {
if (from === 'build') {
return () => ({
__esModule: true,
default: pg,
});
} else {
return {
default: pg,
};
}
};
return {
name: 'offline-remote-plugin',
errorLoadRemote({ id, error, from, origin }) {
console.error(id, 'offline');
const pg = function () {
console.error(id, 'offline', error);
return getErrorMessage(id, error);
};
return getModule(pg, from);
},
};
}
内联样式
shared: {
...shareConfig,
'css-loader': { singleton: true, requiredVersion: false },
'style-loader': { singleton: true, requiredVersion: false },
'sass': { singleton: true },
' sass-loader': { singleton: true },
},
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于