动态加载 remoteEntry.js 文件
原文由 Alex O'Callaghan 于 发布,订阅该博客
Webpack Module Federation 可用于支撑微前端 Web 应用架构。通过加载 remoteEntry.js 文件即可加载独立部署的远程应用。动态加载这些文件可以让你更好地控制性能和缓存,并实现 A/B 测试或分支发布等功能。
在 Mintel,我们在外壳“宿主”应用中使用 Module Federation 来加载由多个独立自治团队分别维护的子应用。关于我们转向这一架构的历程,可阅读 “Adopting a micro-frontend architecture” 一文了解更多细节。
默认情况下,Webpack Module Federation 会为每个远程应用加载 remoteEntry.js 文件。随着团队不断开发新应用,我们的宿主应用中接入了大量远程应用。但我们其实并不需要一次性全部加载——每个应用都可以独立运行,用户也常常只在一个应用内完成操作,而不会在各应用之间来回切换。一次性加载如此多的 remoteEntry.js 文件已经对应用的初始加载时间造成了影响。
采用 动态远程容器 方案,你就可以自主控制 remoteEntry.js 文件的加载。
从 ModuleFederationPlugin 配置中移除 remotes 字段:
plugins: [
new ModuleFederationPlugin({
name: "host-app",
remotes: {},
}),
];在自己的代码中通过注入 <script> 标签来手动加载 remoteEntry.js:
const remoteEntryUrl = "https://something/remote-app/remoteEntry.js";
const scope = "remote-app";
const moduleName = "App";
await __webpack_init_sharing__("default");
await new Promise<void>((resolve, reject) => {
const element = document.createElement("script");
element.src = remoteEntryUrl;
element.type = "text/javascript";
element.async = true;
element.onload = () => {
element.parentElement?.removeChild(element);
resolve();
};
element.onerror = (err) => {
element.parentElement?.removeChild(element);
reject(err);
};
document.head.appendChild(element);
});
// Initialize the federated module
const container: any = window[scope as any];
await container.init(__webpack_share_scopes__.default);
// Fetch module exposed by the federated module
const factory = await container.get(moduleName);
return factory();module-federation-import-remote 这个包可以为你封装上述逻辑:
import { importRemote } from "module-federation-import-remote";
importRemote({ url: "https://something/remote-app", scope: "remote-app", module: "App" }).then((App) => {...});
// If App is a React component you can use it with lazy and Suspense just like a dynamic import:
const App = lazy(() => importRemote({ url: "https://something/remote-app", scope: "remote-app", module: "App" }));
return (
<Suspense fallback={<div>Loading App...</div>}>
<App />
</Suspense>
);通过这种方式,我们将 remoteEntry.js 的加载推迟到真正需要渲染某个 React 组件时,从而提升了初始加载性能。对远程应用加载方式的这种掌控,还能让你在运行时动态加载不同的 remoteEntry.js 文件,例如根据功能开关或用户属性来决定加载哪个文件。
importRemote 默认还会在 remoteEntry.js 的 URL 上添加用于清除缓存的查询参数,以确保这些入口文件不会被缓存。要注意查询字符串清除缓存方式的局限性,相关讨论见这个 GitHub 讨论——你可能还需要考虑 CDN 的配置,或引入专门的服务来管理远程应用的版本。
延伸阅读:
随机一篇博客
评论
登录后参与讨论