一文搞懂微前端

一. 微前端的背景和动机

单页应用

单页应用往往是一个庞大的前端项目,由一个团队或多个团队共同开发,使用同一套技术栈,打包成一个整体,部署在一个域名下

随着 Web 应用的功能越来越丰富和复杂,单页应用不得不面临以下问题:

  • 技术栈的选择和升级受限,难以适应不同的业务需求和技术发展。
  • 项目的可维护性和可测试性降低,代码的耦合度高,模块的划分不清晰,变更的风险大。
  • 项目的构建和发布效率低下,打包的体积大,加载的时间长,部署的频率低。

开发和维护成本也越来越高,为了解决这些问题,微前端的概念应运而生。

微前端

将一个大型的前端应用拆分成多个小型的前端应用,每个前端应用可以由不同的团队开发,使用不同的技术栈,独立部署,最后在一个统一的入口进行聚合展示。这样,每个前端应用可以专注于自己的业务领域,实现高内聚,低耦合,提高开发效率和质量。

优点

  • 技术栈无关,让不同的团队可以使用自己熟悉的技术开发和部署子应用;
  • 维护成本低,独立开发、独立部署,提高开发效率和灵活性;
  • 应用之间的高效解耦,避免业务模块间的耦合导致的复杂性和风险;
  • 平滑迁移和升级框架和系统,提升用户体验和满意度。

缺点

  • 额外的开发、学习成本,需要设计和实现一套微前端的框架和协议;
  • 通信和协作问题,需要定义和遵守应用之间的一套通信规范和接口;
  • 隔离和安全问题,需要考虑应用之间样式隔离、沙箱隔离、权限控制等方面;
  • 一致性和可用性问题,需要保证应用的风格统一、版本一致、错误处理等方面

二. 微前端的实现方案和框架

实现微前端的方案有多种,主要可以分为以下几类:

  • 路由分发式:通过路由将不同的业务分发到不同的独立前端应用上,通常通过 HTTP 服务的反向代理或者浏览器端的路由拦截来实现。这种方案的优点是简单易实现,缺点是应用间的切换会有页面刷新,用户体验不佳。
  • iframe 嵌套式:通过 iframe 将不同的前端应用嵌套在一个主应用中,实现应用间的隔离和集成。这种方案的优点是兼容性好,隔离性强,缺点是 iframe 有很多限制,如布局,跨域,通信,性能等问题。
  • Web Components 组件式:通过 Web Components 标准将不同的前端应用封装成自定义元素,然后在主应用中使用这些元素,实现应用间的组合和复用。这种方案的优点是符合 Web 标准,组件化程度高,缺点是兼容性差,需要 polyfill 支持,而且有一定的学习成本。
  • 组合式应用路由分发式:通过在主应用中动态加载和渲染不同的前端应用,实现应用间的无缝切换和集成。这种方案的优点是用户体验好,技术栈无关,缺点是实现难度高,需要解决应用间的路由,隔离,通信等问题。

目前,市面上已经有一些成熟的微前端框架,如 single-spa,qiankun,icestark 等,它们都是基于组合式应用路由分发微前端的方案,提供了一些通用的能力和接口,帮助开发者快速搭建微前端系统。

三. 微前端的常见问题:

  • 路由系统:如何实现子应用的切换和卸载,以及主框架和子应用之间的路由协调。一种解决方案是使用 single-spa 库,它提供了一套基于 url 的路由机制,可以动态加载和卸载子应用,同时支持多种技术栈的集成¹²。
  • 资源加载:如何实现子应用的动态加载和隔离,以及主框架和子应用之间的资源共享。一种解决方案是使用 HTML Entry 的方式,即将子应用打包成一个 HTML 文件作为入口,主框架通过 fetch html 的方式获取子应用的静态资源,并将 HTML document 插入到主框架的容器中。
  • 状态管理:如何实现子应用之间的通信和数据共享,以及主框架和子应用之间的状态同步。一种解决方案是使用自定义事件或全局变量的方式,实现跨应用的事件监听和数据传递,同时避免状态的滥用和污染。
  • 样式隔离:如何实现子应用的样式不影响主框架和其他子应用,以及主框架和子应用之间的样式统一。一种解决方案是使用 Shadow DOM 或 CSS Modules 的方式,实现样式的作用域隔离,同时遵循一套统一的 UI 设计规范和主题变量。

-----------------------------------------进阶部分 以下主要以qiankun为例--------------------------------

微前端的路由分发机制

根据浏览器的 URL 变化来切换不同的微应用,以及在微应用之间同步路由状态。一般来说,微前端的路由分发机制可以分为两种模式:hash 模式和 history 模式。

hash 模式是指使用 URL 的 hash(#)部分来标识不同的微应用,例如 http://example.com/#/app1/foo 表示 app1 应用的 foo 路由,http://example.com/#/app2/bar 表示 app2 应用的 bar 路由。这种模式的优点是实现简单,兼容性好,缺点是不利于 SEO,而且 hash 的长度有限制。

history 模式是指使用 URL 的 pathname(/)部分来标识不同的微应用,例如 http://example.com/app1/foo 表示 app1 应用的 foo 路由,http://example.com/app2/bar 表示 app2 应用的 bar 路由。这种模式的优点是 URL 更美观,更利于 SEO,缺点是需要服务端的支持,而且实现复杂度高。

无论是哪种模式,微前端的路由分发机制都需要解决以下几个问题:

  • 如何在主应用中识别和匹配微应用的路由
  • 如何在主应用中激活和切换微应用
  • 如何在微应用中获取和更新路由状态
  • 如何在主应用和微应用之间保持路由一致性

对于第一个问题,一种常见的做法是在注册微应用时,指定一个匹配规则,例如正则表达式,函数,或者字符串,来判断当前的 URL 是否属于某个微应用。例如,qiankun 提供了一个 activeRule 参数,可以是一个正则表达式,如 /app1/,也可以是一个函数,如 location => location.pathname.startsWith('/app1'),来确定是否激活 app1 应用。

对于第二个问题,如何在主应用中激活和切换微应用,一种常见的做法是使用 single-spa 的 startnavigateToUrl 方法,来启动微前端系统,以及在不同的微应用之间跳转。例如,qiankun 在主应用中调用 start() 方法,来初始化微前端系统,然后在主应用的导航栏中,使用 navigateToUrl 方法,来实现微应用的切换,如 navigateToUrl('/app1/foo')

对于第三个问题,如何在微应用中获取和更新路由状态,一种常见的做法是使用浏览器的 history API,来监听和修改 URL 的变化,以及使用 location 对象,来获取当前的 URL 信息。例如,qiankun 在微应用中调用 history.pushStatehistory.replaceState 方法,来更新 URL 的 pathname 部分,以及使用 location.pathname 属性,来获取当前的 pathname 值。

对于第四个问题,如何在主应用和微应用之间保持路由一致性,一种常见的做法是使用 popstate 事件,来监听 URL 的变化,以及使用 window 对象,来获取当前的 URL 信息。例如,qiankun 在主应用和微应用中都注册了 popstate 事件的监听器,来响应 URL 的变化,以及使用 window.location 对象,来获取当前的 URL 信息。

微前端的应用隔离策略

微前端的应用隔离策略是指如何保证不同的微应用之间不会相互干扰,造成全局变量,样式,事件等的冲突。一般来说,微前端的应用隔离策略可以分为以下几种:

  • JS 沙箱:通过代理或重写全局对象,如 windowdocumentlocalStorage 等,来实现微应用的 JS 隔离。例如,qiankun 使用了 Proxy 对象,来拦截对全局对象的访问和修改,以及使用了 snapshot 方法,来保存和恢复全局对象的状态。
  • CSS 隔离:通过添加命名空间,作用域,或者 Shadow DOM,来实现微应用的 CSS 隔离。例如,qiankun 使用了 prefix 参数,来给微应用的样式添加一个前缀,以及使用了 shadow 参数,来给微应用创建一个 Shadow DOM。
  • DOM 隔离:通过添加容器元素,或者 Shadow DOM,来实现微应用的 DOM 隔离。例如,qiankun 使用了 container 参数,来给微应用指定一个容器元素,以及使用了 shadow 参数,来给微应用创建一个 Shadow DOM。

微前端的消息通信方式

微前端的消息通信方式是指如何在主应用和微应用之间,以及在不同的微应用之间,进行数据的传递和同步。一般来说,微前端的消息通信方式可以分为以下几种:

  • props 传递:通过在主应用中给微应用传递一些属性,来实现数据的传递。例如,qiankun 提供了一个 props 参数,可以是一个对象,如 { name: 'app1' },也可以是一个函数,如 () => ({ name: 'app1' }),来给微应用传递一些属性。
  • 事件广播:通过在主应用和微应用中使用自定义事件,来实现数据的广播和订阅。例如,qiankun 提供了一个 emit 方法,来在主应用中触发一个自定义事件,如 emit('foo', 'bar'),以及一个 on 方法,来在微应用中监听一个自定义事件,如 on('foo', data => console.log(data))
  • 全局状态:通过在主应用中维护一个全局状态对象,来实现数据的共享和同步。例如,qiankun 提供了一个 initGlobalState 方法,来在主应用中初始化一个全局状态对象,如 const { onGlobalStateChange, setGlobalState } = initGlobalState({ count: 0 }),以及一个 getMicroAppStateActions 方法,来在微应用中获取一个全局状态对象的操作方法,如 const { onGlobalStateChange, setGlobalState } = getMicroAppStateActions()

微前端适用场景

微前端的适用场景有以下几个:

  • 大型复杂的 Web 应用,如电商,门户,企业级等,需要支持多个业务领域,多个团队,多个技术栈,多个版本等。
  • 需要进行应用的重构或者迁移,如从老旧的技术栈迁移到新的技术栈,或者从单体应用拆分成微服务等。
  • 需要提高应用的开发效率和质量,如实现敏捷开发,持续集成,持续交付等。

结语

微前端是一种前沿的 Web 应用架构模式,它可以帮助开发者将一个庞大的前端应用拆分成多个小型的前端应用,实现技术栈的自由选择,业务模块的独立开发,应用部署的快速迭代,以及应用架构的增量演进。微前端也有一些挑战和限制,需要开发者根据自己的实际情况,选择合适的方案和框架,以及解决应用间的路由,隔离,通信等问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值