微前端
什么是微前端?
微前端(Micro Frontends)是前端领域中的一种架构思想,类似于微服务(Microservices)在后端的应用。微前端的主要目标是将一个大的前端应用拆分成若干个独立的、可部署的、技术栈不同的子应用(微应用),这些子应用可以独立开发、测试、部署和运行,最终通过某种机制集成到一个统一的用户界面上。
微前端的核心思想:
- 独立开发、独立部署:每个微应用可以独立开发和部署。
- 技术栈无关:每个微应用可以使用不同的技术栈,比如 Vue、React、Angular 可以混合使用。
- 解耦与模块化:通过微前端架构,解耦大型应用,提升可维护性。
- 独立运行:每个微应用可以独立运行,不依赖其他微应用。
常用的微前端框架及技术方案
常见的微前端框架有:
- Single-SPA
- Qiankun
- Module Federation(Webpack 5)
- Iframe-Based
Single-SPA
简介:
Single-SPA 是最早流行的微前端框架之一,它的核心理念是将不同的前端应用(如 React、Vue、Angular)注册为子应用,并且基于路由来动态加载这些子应用。Single-SPA 本身不会限定你的技术栈,你可以自由组合使用不同的框架。
优点:
- 支持多个前端框架共存(React、Vue、Angular 等)。
- 开发社区活跃,有较多的插件和文档。
- 良好的模块隔离机制,可以帮助管理子应用的生命周期。
缺点:
- 需要手动配置,开发者需要了解一定的底层实现。
- 子应用之间的依赖可能导致较复杂的通信和共享机制。
- 学习曲线稍高。
示例:
一个简单的 Single-SPA 项目可能包括两个子应用:一个 React 应用和一个 Vue 应用。
1 | npm install single-spa |
配置子应用:
1 | import { registerApplication, start } from 'single-spa'; |
实现步骤:
- 创建一个主应用(root config)。
- 注册各个子应用,并通过路由来加载不同的子应用。
- 使用
start()
启动微前端系统。
Qiankun
Qiankun 是基于 Single-SPA 之上的一套微前端框架,由阿里巴巴蚂蚁金服团队开发。它的特点是开箱即用,提供了更简单的 API 和更强的隔离机制,使开发者可以快速搭建微前端应用。相比 Single-SPA,Qiankun 的使用更加简单,并且提供了很多额外的功能。
优点:
- 基于 Single-SPA,但更易用,配置更加简洁。
- 提供了样式隔离、JS 沙箱等增强功能,确保子应用之间的隔离。
- 提供了丰富的文档和教程,易于上手。
- 支持子应用的独立开发和调试。
缺点:
- 对于复杂场景,仍然需要开发者做一些额外的配置。
- 尽管 Qiankun 解决了一些单体架构的问题,但子应用之间的依赖和耦合仍需开发者处理。
示例:
一个简单的 Qiankun 主应用和子应用的配置:
安装 Qiankun:
1 | npm install qiankun |
主应用:
1 | import { registerMicroApps, start } from 'qiankun'; |
子应用(如 React 应用):
1 | import { render } from 'react-dom'; |
实现步骤:
- 安装
qiankun
,并在主应用中注册子应用。 - 每个子应用实现
bootstrap
、mount
、unmount
等生命周期方法。 - 使用
start()
启动微前端应用。
qiankun实现样式隔离的方法
动态样式表隔离
当一个子应用加载时,Qiankun 会拦截该子应用中所有的
style
和link
标签,并将它们动态挂载到当前子应用的 DOM 结构内,而不是全局作用域。每当子应用被卸载时,Qiankun 会移除这些样式表,确保它们不会影响其他子应用或主应用的样式。
- 动态样式表隔离(Dynamic StyleSheet Isolation):通过动态处理
style
和link
标签,确保子应用的样式只在它的作用域中生效。 - CSS 沙箱(CSS Isolation with Shadow DOM,实验性):通过 Shadow DOM 技术进一步隔离样式,使其与外部完全分离。
CSS 沙箱(Shadow DOM 隔离)
每个子应用都可以被封装到一个
shadowRoot
中,shadowRoot
是一个独立的 DOM 子树,具有自己独立的样式作用域。其内部样式不会影响外部,也不会被外部样式影响。当子应用被封装在 Shadow DOM 中时,该子应用的所有样式都只作用于该shadowRoot
内的 DOM 元素。
Module Federation(Webpack 5)
Module Federation 是 Webpack 5 中引入的功能,它允许多个独立打包的应用共享模块和依赖。这使得微前端应用之间可以高效地共享代码,比如在不同的子应用中共享某个库或组件,而不需要重复打包。
优点:
- 基于 Webpack 原生支持,使用时无需额外的微前端框架。
- 允许多个应用共享依赖和模块,减少重复代码和加载时间。
- 支持独立开发、独立部署,并且可以动态加载模块。
缺点:
- 对 Webpack 配置要求较高,开发者需要深入了解 Webpack。
- 仅支持 Webpack 项目,限制了一些非 Webpack 构建的项目。
示例:
使用 Webpack 5 Module Federation 配置微前端:
1 | // webpack.config.js (主应用) |
实现步骤:
- 在 Webpack 配置中使用
ModuleFederationPlugin
。 - 定义主应用和子应用之间的模块共享规则。
- 每个子应用都打包为独立的模块,主应用可以动态加载和使用这些模块。
Iframe微前端
使用 <iframe>
标签是实现微前端最简单的方式。通过将不同的子应用嵌入到 iframe 中,可以轻松实现隔离和独立部署。不同子应用之间不会共享样式和 JS 全局变量,因为 iframe 天然隔离了作用域。
优点:
- 完全隔离:每个子应用有自己独立的作用域,避免样式和 JS 的污染。
- 实现简单:使用浏览器的原生 iframe 标签,无需额外依赖。
缺点:
- 体验较差:iframe 导致跨子应用的通信变得复杂。
- 性能问题:iframe 的渲染性能较差,且嵌套 iframe 会导致加载时间增加。
- SEO 友好性差:iframe 中的内容不利于 SEO 优化。
- url 不同步。浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。当使用iFrame嵌入内容时,浏览器会默认缓存iFrame加载的页面。这意味着当嵌入的页面内容发生更新时,浏览器可能仍然展示旧内容,而不是新内容。这是因为浏览器认为嵌入的页面没有发生变化,因此加载缓存中的旧版本。解决iFrame缓存问题的一种常用方法是通过在iFrame的URL中添加随机参数来强制浏览器重新加载内容。这样,每次加载iFrame时,URL都会不同,浏览器会认为内容发生了变化,从而加载最新的内容。
- 全局上下文完全隔离,内存变量不共享。iframe 内外系统的通信、数据同步等需求,主应用的 cookie 要透传到根域名都不同的子应用中实现免登效果。子应用需要和基座共享cookie的话,条件还是比较苛刻的,需要主域名一致
在主应用中通过 <iframe>
嵌入子应用:
1 | <iframe src="http://localhost:3000/react-app" width="100%" height="100%"></iframe> |
实现步骤:
- 为每个子应用提供一个独立的 URL,并通过 iframe 嵌入。
- 可以通过
postMessage
来实现跨 iframe 的通信。
微前端架构的优缺点
优点:
- 技术栈无关:允许多个团队使用不同的前端技术栈开发子应用。
- 独立部署:每个子应用可以独立构建和部署,不影响其他子应用。
- 团队独立:每个团队可以独立管理自己的子应用,减少沟通和协作成本。
- 渐进升级:可以逐步将旧的单体应用迁移到微前端架构中,无需一次性重写整个应用。
缺点:
- 复杂性:需要解决子应用之间的依赖、共享资源、样式隔离等问题。
- 性能问题:如果多个子应用在一个页面中加载,可能会导致性能问题,如重复加载相同的依赖。
- 开发体验:虽然各个子应用独立,但在开发过程中需要额外的工具来管理开发环境、调试等。
微前端应用中的关键问题
- 子应用之间的通信:可以通过全局状态管理、
window.postMessage
、CustomEvent
等来实现。 - 样式隔离:可以通过 CSS Module、Scoped CSS 或者像 Qiankun 提供的沙箱机制来处理。
- 性能优化:通过共享依赖、懒加载等手段来优化微前端的性能。
总结
微前端是一种强大的前端架构,可以解决大型项目中的开发、部署和维护问题。根据具体的需求,你可以选择不同的实现方案:
- 如果你想要高度灵活性,可以选择 Single-SPA。
- 如果你想要快速上手并获得开箱即用的功能, Qiankun 是一个优秀的选择。
- 如果你已经在使用 Webpack 5,并且需要模块共享功能,可以使用 Module Federation。
- 如果你只需要简单的隔离方案,或者快速实现,可以使用 Iframe-based 的方案。
每种技术方案都有它的应用场景和优缺点,学习和掌握这些工具后,你可以根据项目的具体需求灵活选择。