【解决方案】微前端实现方案
2023/07/21 14:33:30
单一项目随着时间推移,规模会越来越大,以至于难以维护。
微前端的思路就是将大应用拆分为若干个小应用,每个小应用都独立开发、部署。
实现思路
MPA
将系统分为多个仓库维护,在首页聚合所有平台的入口或提供统一的导航组件,采用 MPA(Multi-page Application)多页应用模式。
存在以下缺点:
- 只能以页面维度拆分,无法拆分至区块部分。
- 用户在使用时体验感不如 SPA 应用。
- 不同系统间无法直接通信。
- 公共部分更新时,所有子项目都要跟着更新。
iframe 嵌套子项目
iframe 可以保证样式和全局变量的良好隔离,但他的最大问题也在于他的隔离性无法被突破,导致应用间上下文无法被共享,随之带来的开发体验、产品体验的问题。
存在以下缺点:
URL 不同步。浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。
UI 不同步,DOM 结构不共享。如无法显示整页弹窗。
全局上下文完全隔离,内存变量不共享。iframe 内外系统的通信、数据同步等需求,主应用的 cookie 要透传到根域名都不同的子应用中实现免登效果。
加载慢,每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程。
js 加载子应用
将子应用打包成 js 文件,通过 script 标签引入,每个子应用按约定暴露出相应的生命周期钩子,并且在加载后将其绑定到 window 对象下给主应用访问。然后主应用程序确定渲染哪个子应用,调用相关渲染函数传入渲染节点。
<html>
<head>
<title>Feed me!</title>
</head>
<body>
<h1>Welcome to Feed me!</h1>
<!-- These scripts don't render anything immediately -->
<!-- Instead they attach entry-point functions to window' -->
<script src="https://browse.example.com/bundle.js"></script>
<script src="https://order.example.com/bundle.js"></script>
<script src="https://profile.example.com/bundle.js"></script>
<div id="micro-frontend-root"></div>
<script type="text/javascript">
// These global functions are attached to window by the above scripts
const microFrontendsByRoute = {
"/": window.renderBrowseRestaurants,
"/order-food": window.renderOrderFood,
"/user-profile": window.renderUserProfile,
};
const renderFunction = microFrontendsByRoute[window.location.pathname];
// Having determined the entry-point function, we now call it,// giving it the ID of the element where it should render itself
renderFunction("micro-frontend-root");
</script>
</body>
</html>
存在以下缺点:
- 对现有项目来说改造成本高,需要将子项目打包成 js 文件。
- 丧失了按需加载、首屏资源加载优化、css 独立打包等优化措施。
webpack5 提供了模块联邦功能,通过模块联邦可以在多个应用中任意导入/导出模块,从而实现模块的共享。使用模块联邦可以一定程度上减少项目改造的成本。