微服务-微前端

微前端

诞生背景

  1. 微服务
    拆分多个核心功能,关注点更集中,使用不同技术栈,更好维护
  2. 微前端的产生
    基于微服务的理念,各个服务模块单独部署,避免耦合代码回归问题,大型应用开发手段

微前端架构的特点

  1. 简单、松耦合的代码库:微前端架构下的代码库倾向于更小/简单、更容易开发。避免模块间不合理的隐式耦合造成的复杂度上升。通过界定清晰的应用边界来降低意外耦合的可能性,增加子应用间逻辑耦合的成本,促使开发者明确数据和事件在应用程序中的流向。
  2. 增量升级:在面对各种复杂场景时,通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略。因为是运行时加载,可以在没有重建的情况下添加,删除或替换前端的各个部分。
  3. 独立部署:每个微前端都具备有自己的持续交付流水线(包括构建、测试并部署到生产环境),并且能独立部署,不必过多考虑其它代码库和交付流水线的当前状态。
  4. 团队自治:各个团队独立开发,相互不影响,独立开发、独立部署,微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新。

微前端实现方案

  1. iframe
  • 特点:能兼容所有的浏览器,提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决。天然隔离环境
  • 缺点:
    不是单页应用,导致许多功能无法正常在主应用中展示
    url 不同步。浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用
    b. UI 不同步,DOM 结构不共享。想象一下屏幕右下角 1/4 的 iframe 里来一个带遮罩层的弹框,同时我们要求这个弹框要浏览器居中显示,还要浏览器 resize 时自动居中
    全局上下文完全隔离,内存变量不共享。iframe 内外系统的通信、数据同步等需求,主应用的 cookie 要透传到根域名都不同的子应用中实现免登效果。
    慢,每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程
    iframe的特性导致搜索引擎无法获取到其中的内容,进而无法实现应用的 seo
  1. Nginx
    实现:通过配置ngin拦截指定的url返回对应的html模板
    反向代理,路由分發應用,实现应用串联
  • 优点:实现简单、技术栈独立
  • 缺点:需要额外的Nginx配置、与服务端耦合
  1. single-spa
    是通过监听 url change 事件,在路由变化时匹配到渲染的子应用并进行渲染,这个思路也是目前实现微前端的主流方式。同时 single-spa 要求子应用修改渲染逻辑并暴露出三个方法:bootstrap、mount、unmount,分别对应初始化、渲染和卸载,这也导致子应用需要对入口文件进行修改
    https://zh-hans.single-spa.js.org/docs/getting-started-overview/
  • 缺点
    上手成本高
    需要改造现有应用
    样式隔离需要单独处理
  1. qiankun
    建立在single-spa之上实现沙箱隔离
    https://qiankun.umijs.org/zh/guide
  2. EMP
    作为最年轻微前端解决方案,也是吸收了许多 web 优秀特性才诞生的,它在实现微前端的基础上,扩充了跨应用状态共享、跨框架组件调用、远程拉取ts声明文件、动态更新微应用等能力。同时,细心的小伙伴应该已经发现,EMP 能做到第三方依赖的共享,使代码尽可能地重复利用,减少加载的内容。
    https://github.com/efoxTeam/emp
  3. MicroApp
    并没有沿袭 single-spa 的思路,而是借鉴了 WebComponents 的思想,通过 CustomElement 结合自定义的 ShadowDom,将微前端封装成一个类 WebComponents 组件,从而实现微前端的组件化渲染。并且由于自定义 ShadowDom 的隔离特性,MicroApp 不需要像 single-spa 和 qiankun 一样要求子应用修改渲染逻辑并暴露出方法,也不需要修改 webpack 配置,是目前市面上接入微前端成本最低的方案。
    https://gitcode.net/mirrors/micro-zoe/micro-app?utm_source=csdn_github_accelerator

qiankun

【是什么】

是基于 single-spa 进行封装,所以single-spa 特点也被 qiankun 继承下来,并且需要对 webpack 配置进行一些修改。qiankun 基本上可以称为单页版的 iframe,具有沙箱隔离及资源预加载的特点,几乎无可挑剔

【特性】

  • 📦 基于 single-spa 封装,提供了更加开箱即用的 API。
  • 📱 技术栈无关,任意技术栈的应用均可 使用/接入,不论是 React/Vue/Angular/JQuery 还是其他等框架。
  • 💪 HTML Entry 接入方式,让你接入微应用像使用 iframe 一样简单。
  • 🛡​ 样式隔离,确保微应用之间样式互相不干扰。
  • 🧳 JS 沙箱,确保微应用之间 全局变量/事件 不冲突。
  • ⚡️ 资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度。
  • 🔌 umi 插件,提供了 @umijs/plugin-qiankun 供 umi 应用一键切换成微前端架构系统。

【它是如何工作的】

  1. 安装 qiankun
    $ yarn add qiankun # 或者 npm i qiankun -S
  2. 在主应用中注册微应用
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
  {
    name: 'react app', // app name registered
    entry: '//localhost:7100',
    container: '#yourContainer',
    activeRule: '/yourActiveRule',
  },
  {
    name: 'vue app',
    entry: { scripts: ['//localhost:7100/main.js'] },
    container: '#yourContainer2',
    activeRule: '/yourActiveRule2',
  },
]);

start();

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

如果微应用不是直接跟路由关联的时候,你也可以选择手动加载微应用的方式:

import { loadMicroApp } from 'qiankun';

loadMicroApp({
  name: 'app',
  entry: '//localhost:7100',
  container: '#yourContainer',
});
  1. 导出相应的生命周期钩子
    微应用需要在自己的入口 js (通常就是你配置的 webpack 的 entry js) 导出 bootstrap、mount、unmount 三个生命周期钩子,以供主应用在适当的时机调用。
/**
 * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
 * 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
 */
export async function bootstrap() {
  console.log('react app bootstraped');
}

/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
export async function mount(props) {
  ReactDOM.render(<App />, props.container ? props.container.querySelector('#root') : document.getElementById('root'));
}

/**
 * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
 */
export async function unmount(props) {
  ReactDOM.unmountComponentAtNode(
    props.container ? props.container.querySelector('#root') : document.getElementById('root'),
  );
}

/**
 * 可选生命周期钩子,仅使用 loadMicroApp 方式加载微应用时生效
 */
export async function update(props) {
  console.log('update props', props);
}
  1. 配置微应用的打包工具
    除了代码中暴露出相应的生命周期钩子之外,为了让主应用能正确识别微应用暴露出来的一些信息,微应用的打包工具需要增加如下配置:
    webpack:
const packageName = require('./package.json').name;

module.exports = {
  output: {
    library: `${packageName}-[name]`,
    libraryTarget: 'umd',
    jsonpFunction: `webpackJsonp_${packageName}`,
  },
};

相关配置介绍可以查看 webpack 相关文档

总结

  • 实现原理
  • 解决跨域
    微应用需要设置允许跨域访问主应用才能加载微应用的资源
  • 开发环境:
    需要设置打包配置文件的 devServer 的 headers 属性
headers: {
    'Access-Control-Allow-Origin': '*',
}
  • 生产环境:
    微应用nginx 需要配置:
    'Access-Control-Allow-Origin': '主应用域名' 或者 'Access-Control-Allow-Origin': '*'
  • 脚本隔离-一种是快照拷贝的方式,一个是基于proxy的方式
    乾坤会根据当前环境是否支持proxy来决定用那种方式。
  • 样式隔离-域隔离和shadow dom
  • 为每个css规则添加特定的前缀来起到隔离的作用,例如微应用中的样式是p{color:#000},处理后为.app1 p {color:#000} 。
  • 当前微应用的根节点开启shadow,然后子节点的操作都是在shadowRoot上来进行隔离。
    • 沙盒主要作用就是隔离微应用之间的脚本和样式影响,需要处理style、link、script类型的标签。对于处理的时机第一个是在首次加载的时候,第二个是在微应用运行中。在运行中的处理方案就是乾坤重写了下面原生的方法,这样就可以监听到新添加的节点,然后对style、link、script标签进行处理
  • 开发实现上子模块希望隔离,但用户真实使用是有聚合(页面甚至平台级组合)诉求的,有没有好的经验分享解决这样的问题?
  • qiankun 在性能优化、提升子应用打开速度方面做了哪些工作?
    最基本的有 prefetch 这种配置,开了这个配置可以提前将一些还不需要渲染的微应用的静态资源做一下预加载。
    实践中会有微应用特别多,预加载请求就会很多的情况。
    prefetch 可以配置成数组的形式,指定加载哪些微应用。如果有平台级别的数据统计方案,prefetch 对应的数组可以根据应用打开率动态决策。
  • 是否支持 vite 来构建应用
    不支持。因为 esm 的机制导致没办法把 js 拿来做手动 evaluate,因为要支持沙箱
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值