基础扫盲

微前端简介

什么是微前端

微前端是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。各个前端应用可以独立运行、独立开发、独立部署

微服务与微前端原理和软件工程,面向对象设计中的原理同样相通,都是遵循单一职责、关注分离、模块化与分而治之等基本的原则

微前端的优缺点

  • 优点
    • 可以与时俱进,不断引入新技术/新技术
    • 局部/增量升级
    • 代码简洁、解耦、易维护
    • 独立部署
    • 组织更具扩展能力,其团队更加独立自治
  • 缺点
    • 重复依赖
    • 团队之间更加分裂

微前端应用场景

  1. 兼容遗留系统
  2. 应用聚合
  3. 团队间共享:其低内聚高耦合特性,使得高质量的共享成为可能
  4. 局部/增量升级

微前端要克服的几个障碍

  1. 资源的隔离:由于存在不同应用各自定义CSS和全局变量的情况,应用聚合时需要考虑彼此之间的影响。应用JS 沙箱和 CSS 隔离等相关技术,使各应用之间互不影响
  2. 应用的注册
  3. 对性能的影响:按需加载、预加载、公共依赖加载
  4. 应用间通信
  5. 应用嵌套/并行

微前端实现的几种方式

  1. 路由分发式微前端:即通过路由将不同的业务分发到不同的、独立前端应用上。其通常可以通过 HTTP 服务器的反向代理来实现,又或者是应用框架自带的路由来解决
  2. 使用 iFrame 创建容器,使用前提:不需要 SEO、拥有相应的应用管理机制
  3. 自制框架兼容应用
  4. 组合式集成:将应用微件化
  5. 纯 Web Components 技术构建:Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的 Web 应用中使用它们
  6. 结合Web Components构建
  7. 在Web Components中集成现有框架
  8. 集成在现有框架中的 Web Components

如何落地微前端一体化运营工作台

qiankun 的使用
1.png
运行在主应用的子应用发起的请求配置其经过主应用的网关层,通过服务层处理其跨域、登录、转发等逻辑

微前端体系下的 plus

  1. 性能优化:公共资源只加载一遍;即把子应用公共依赖的大版本对齐,将所有公共依赖抽离出来,只在进入主应用时候加载这一份,由于 CDN 地址一样,那么子应用不会重复加载
  2. 体验的度量
  3. 反馈跟踪

交互设计统一模式:同类统一;舒服对齐;不常用的收起;简单不阻碍

如何分三步来探索微前端架构落地

为什么需要微前端

  1. 业务价值
    1. 内部应用太多:域名繁多,记忆成本高
    2. UI 风格不一致:多应用各自团队维护,风格不一致
    3. 多应用操作断层:例如公共头改造,需要在各应用中全量修改
  2. 工程价值
    1. 统一管理:流程机械不连贯,沟通成本高
    2. 模块拆分多人合作
    3. 发布提速

微前端可能遇到的问题

2.png
iFrame:可解决全局样式冲突、JS 污染

  • 存在的问题:区块中加载子应用,子应用导航之后,用户刷新区块页面,子应用导航会回到初始状态

应用集成

  1. Luigi:基于 iFrame 的,不可取
  2. Single-Spa:SystemJs or other,是一个裸库/加载框架,样式隔离、JS执行没有任何包装,模块加载还需要借助 SystemJs 这样的库
  3. Qiankun:single-spa + sandbox + import-html-entry,基于 Single-Spa 进行封装,路由已经做过处理,利用 import-html-entry 实现了样式隔离

实际遇到的问题:重复复配置、DLL、AntD Modal、父子通讯、多Store 共存

应用集成模式

  1. 简单模式:整页覆盖渲染 + 导航器浮层
  2. 精细模式:提供 Content 渲染区域给子应用

如何在字节设计与实践微前端沙盒

沙盒应该做什么

iframe-困难重重

  1. 特点
    1. 站点页面被拆分为 N 个 iframe,每个iframe 单独一个域名
    2. 独立上下线、独立运行时
  2. 问题
    1. 难以 deeplinking
    2. 共用数据困难:登录身份、站内信、跨模块通信
    3. 存在公用代码、加载优化、运行优化等问题

沙盒像什么

像 Docker

  1. 开发者必须体会不到环境差别
  2. 运行时没有环境差异
  3. 服务端微服务的基石

沙盒怎么做

  1. 参考单核、操作系统进程模拟进程切换策略
    1. JavaScript 是单线程的
    2. 通过对路由切换的封装,模拟单进程
    3. 通过对事件循环封装,模拟单核多进程
  2. 用 Context 切换模拟线程安全
    1. 新沙盒即将激活时,查找当前激活中的沙盒
    2. 保存现场,存储 context、恢复之前的 context
  3. Context 切换的笛卡尔积
    1. 比较并切换
    2. 沙盒数量 N 的笛卡尔平方
    3. 退回“初始” context
    4. 恢复之前 diff 的 context

沙盒到底作什么

  1. CSS 干扰
    1. 独立开发、混合加载:HTML 标准的 CSS 作用域;Scoped CSS
    2. CSS module CSS in JS:DOM header
    3. 单核多进程的情况
    4. CSSStyleSheet.cssRules
  2. 全局变量的干扰
    1. Polyfill 等差异巨大:例如 generatorRuntime;组件模块化;全局的外部环境
    2. Identifier:let;const;class
    3. Configurable
    4. window.location
  3. 所有需要进程安全的对象:DOM 沙盒;cookie;localstorage

如何设计微前端的主子路由调度

微前端内核部分功能模块展开

3.png

主子应用路由调度问题

符合主子应用路由正常调度至少同时满足三个场景用例

  1. 由一个具体的 URL 直达 目标子应用的对应页面
  2. 点击子应用中的链接,跳转对应页面,且主应用路由同步
  3. 点击浏览器后退,正确返回上一个页面,且主应用路由同步

MVC 时代
4.png

页面状态管理发展史
5.png**
Backbone.js 的 Router 巧妙的利用了 hash 本身作为 currentState 这个变量,封装了 hashChange 事件

官方推出的 History API 也基本覆盖了 Controller 的能力,其更强大体验更好,但其并不能完全等同于前端路由,因为它管的是页面状态,额外的可以让我们在页面状态改变时更改 url,但其实本身也支持在不改变 url 的同时改变页面状态

前端路由不是必须!
但我们希望把页面状态暴露给用户,那么就需通过 url 体现,两者形成强关联,通过 url 反馈页面状态

主应用完全不处理路由

  • 主应用不根据路由调度子应用,子应用内部的状态变化按照原样反映到主应用路由
  • 问题:
    • 初始化无法识别路由:主应用没有处理路由,初始化进入不能确定要调用哪个路由,可能只显示主应用
    • 路由冲突:如果两个子应用路由一样,就会发生冲突


子应用和主应用共享路由**

  • 主应用根据路由调度子应用,子应用内部的状态变化根据特定规则反映到主应用的路由
    • 切片分割,要求子应用按照一定格式定义路由,例如路由前面添加 app_name 进行分割,避免路由冲突 ```vue // 使用子应用名称来对共享资源切片 const APP_NAME = ‘cow’;

```

  • 新的问题:需要将约定侵入子应用的逻辑(限定了子应用的路由处理方式)
    • 想到的解决方式:沙箱隔离

子应用维护隔离的路由

  1. 隔离对全局上下文产生的副作用:Closure;Node.js Module
  2. 特别地,隔离 DOM / BOM 对象: