微前端简介

318 阅读6分钟

微服务

  1. 容器化,WSL,开发环境和部署环境完全一致,迁徙无成本。 devops
  2. 颗粒度可控和解耦。
  3. 异构的需求

微前端

微前端(Micro-Frontends)是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。 各个前端应用还可以独立运行、独立开发、独立部署。 微前端不是单纯的前端框架或者工具,而是一套架构体系,这个概念最早在2016年底被提出。

微前端的应用前提和使用场景

前提:

  1. SPA架构,单页面应用
  2. 前端异构

场景: 主要用于项目的拆分和细化;或者历史系统的整合

微前端的早期解决方案

image.png

微前端的模块组成

基座应用 + 微应用(一般微应用之间不直接通信,而是通过基座订阅/触发,然后将结果下发给微应用)

image.png

使用微前端的结果展示

image.png

使用微前端要解决的主要问题

  1. 应用加载

根据注册的子应用,通过给定的url,加载约定格式的子应用入口,并挂载到给定位置。入口方式通常有两种:HTML和JS,JS做入口更纯粹,HTML做入口更易于旧项目改造。此外,提供预加载功能也很有必要,预加载是指在应用尚未渲染时提前加载资源并缓存,从而提升首屏渲染速度

  1. 应用的生命周期

加载、挂载、更新、卸载

  1. 路由同步

子应用的路由切换时,同步更新url;url改变时,同步更新子应用

  1. 主微应用的隔离问题

js隔离

  1. Snapshot
    子应用挂载时,先对全局window变量打个快照放闭包里,再把全局window交给子应用,在子应用卸载时通过快照恢复全局window变量
  2. Sandbox
    Proxy提供的是with和new Function闭包中用到的充当window作用域的对象,通过白名单属性限制能访问真正window上的部分元素,同时对document、history、location进行劫持限制等,从而组成沙箱环境

css隔离
命名约定、自动Scope、Shadow DOM、自动卸载、弹窗遮罩

  1. 通信问题

局部通信和全局通信

微前端架构介绍

qiankun(运行时确定依赖关系)

qiankun 方案是蚂蚁金服开源的一款框架,基于 single-spa 的微前端方案

特点

  • html entry 的方式引入子应用,相比 js entry 极大的降低了应用改造的成本;
  • 完备的沙箱方案,js 沙箱做了 SnapshotSandbox、LegacySandbox、ProxySandbox 三套渐进增强方案,css 沙箱做了 strictStyleIsolation、experimentalStyleIsolation 两套适用不同场景的方案;
  • 做了静态资源预加载能力;

不足

  • 适配成本比较高,工程化、生命周期、静态资源路径、路由等都要做一系列的适配工作;
  • css 沙箱采用严格隔离会有各种问题,js 沙箱在某些场景下执行性能下降严重;
  • 无法同时激活多个子应用,也不支持子应用保活;
  • 无法支持 vite 等 esmodule 脚本运行;

在主应用中注册微应用,当微应用信息注册完之后,一旦浏览器的url发生变化,便会自动触发qiankun的匹配逻辑,所有activeRule规则匹配上的微应用就会被插入到指定的container中,同时依次调用微应用暴露出的生命周期钩子(bootstrap、mount、unmount)

使用
qiankun官网

  • 安装qiankun,$ yarn add qiankun # 或者 npm i qiankun -S
  • 在主应用中注册微应用
  • 在微应用中导出相应的生命周期钩子并配置微应用的打包工具

    微应用要做的具体事项:

    1. 新增 public-path.js 文件,用于修改运行时的 publicPath
    2. 微应用建议使用 history 模式的路由,需要设置路由 base,值和它的 activeRule 是一样的
    3. 在入口文件最顶部引入 public-path.js,修改并导出三个生命周期函数。
    4. 修改 webpack 打包,允许开发环境跨域和 umd 打包。

EMP(构建时确定依赖关系)

基于 webpack5 module federation 的微前端方案。

特点

  • webpack 联邦编译可以保证所有子应用依赖解耦;
  • 应用间去中心化的调用共享模块速度提升
  • 模块远程 ts 支持;

不足

  • 对 webpack 强依赖,老旧项目不友好;
  • 没有有效的 css 沙箱和 js 沙箱,需要靠用户自觉;
  • 子应用保活、多应用激活无法实现;
  • 主、子应用的路由可能发生冲突;
  • 如果不同应用之间是不同的框架,需要借助第三方去解决
  • 本地开发需要开启多个端口的服务,比较麻烦

Module Federation

不同应用分为host和remote

  • host:引用了其他应用的应用
  • remote:被其他应用所使用的应用
    提供了能在当前应用中远程加载其它服务器上应用的能力,基于此可以实现一个去中心化的应用部署群,每个应用是单独部署在各自的服务器,每个应用都可以引用其它应用,也能被其它应用所引用。通过new ModuleFederationPlugin配置被远程引用时的路径(exposes)、远程引用的应用、与其它应用之间可以共享的第三方依赖(shared)

使用
EMP详细讲解
React使用EMP做微前端示例

// emp-config.js文件

const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
  // 其他webpack配置...
  plugins: [
    new ModuleFederationPlugin({
        name: 'empBase',
        library: { type: 'var', name: 'empBase' },
        filename: 'emp.js',
        remotes: {
          app_two: "app_two_remote",
          app_three: "app_three_remote"
        },
        exposes: {
          './Component1': 'src/components/Component1',
          './Component2': 'src/components/Component2',
        },
        shared: ["react", "react-dom","react-router-dom"]
      })
  ]
}
字段名类型含义
namestring必传值,即输出的模块名,被远程引用时路径为${name}/${expose}
libraryobject声明全局变量的方式,name为umd的name
filenamestring构建输出的文件名
remotesobject远程引用的应用名及其别名的映射,使用时以key值作为name
exposesobject被远程引用时可暴露的资源路径及其别名
sharedobject与其他应用之间可以共享的第三方依赖,使你的代码中不用重复加载同一份依赖

Web Components

特点:

  • 浏览器的原生组件,可以创建可重用的定制元素,不必担心代码冲突。
  • 技术栈无关,Web Components是浏览器原生组件,即可以在任何JS框架中使用
  • 独立开发:使用Web Components开发的应用无需依赖其它应用
  • 应用间隔离:Shadow DOM的特性,使得引入的微应用间可以达到相互隔离的效果 不足: Web Components也有浏览器兼容性的限制

主要由3项技术组成

  1. Custom elements(自定义元素):一组JavaScript API,允许定义custom elements及其行为,然后可以在页面中使用。

  2. shadow DOM(影子DOM):一组JavaScript API,用于将封装的“影子”DOM树附加到元素(与主文档DOM分开呈现)并控制其关联的功能。通过这种方式,可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其它部分发生冲突

  3. TML templates(HTML模板):使用和元素可以编写不在呈现页面中显示的标记模板,然后它们可以作为自定义元素结构的基础被多次重用。

micro-app

micro-app 是基于 webcomponent + qiankun sandbox 的微前端方案。

特点

  • 使用 webcomponet 加载子应用相比 single-spa 这种注册监听方案更加优雅;
  • 复用经过大量项目验证过 qiankun 的沙箱机制也使得框架更加可靠;
  • 组件式的 api 更加符合使用习惯,支持子应用保活;
  • 降低子应用改造的成本,提供静态资源预加载能力;

不足

  • 接入成本较 qiankun 有所降低,但是路由依然存在依赖;
  • 多应用激活后无法保持各子应用的路由状态,刷新后全部丢失;
  • css 沙箱依然无法绝对的隔离,js 沙箱做全局变量查找缓存,性能有所优化;
  • 支持 vite 运行,但必须使用 plugin 改造子应用,且 js 代码没办法做沙箱隔离;
  • 对于不支持 webcompnent 的浏览器没有做降级处理;

概念解释

子应用保活
当子应用设置为保活模式,切换子应用后仍然可以保持子应用的状态和路由不会丢失。

子应用嵌套
嵌套的应用和正常应用一致,支持预加载、保活、同步、通信等能力,需要注意的是内嵌的子应用 name 也需要保持唯一性,否则将复用之前渲染出来的应用

多应用激活
一个页面同时激活多个子应用并且保持这些子应用路由同步的能力。

应用共享
一个微前端系统可能同时运行多个子应用,不同子应用之间可能存在相同的包依赖,那么这个依赖就会在不同子应用中重复打包、重复执行造成性能和内存的浪费。