# 微前端(预研)
2020年4月,前期预研
WARNING
此文章是2020年4月,未投入生产时的调研报告,仅作为参考留档。
在实际的使用中,随着对微前端的探索的加深以及业务形态的清晰,微前端也在逐渐改进,请以最终呈现效果为准。
原文:微前端方案预研 - 语雀
# 参考链接
参考qiankun团队给出的微前端分析: 可能是你见过最完善的微前端解决方案
分析很到位,而且与我们的思路很契合
# 基础设计
# 目录结构
├── core # 核心运行库
└── global-provider # 跨模块通信
2
# 包名
yarn add @h3yun/microfrontend
yarn add @h3yun/global-provider
2
3
4
# 第三方框架预研
可借鉴或可能使用的第三方框架
# single-spa
最原始最基础的微前端实现 https://single-spa.js.org/
# qiankun
阿里微前端解决方案,亮点:HTML Entry,JS 沙箱,基于Shadow DOM的样式隔离; https://qiankun.umijs.org
# SystemJS
可以在浏览器运行的动态模块加载器,支持ES6模块规范;在微前端中适合做公共模块的复用; https://github.com/systemjs/systemjs
# MobX
简单、独立的状态管理; https://cn.mobx.js.org/
# import-html-entry
qiankun的作者开发的用来加载HTML Entry的插件,有趣; https://github.com/kuitos/import-html-entry
# 沙箱
通过ES6的Proxy
特性,拦截全局变量设置; 子应用之间,全局变量、事件在各个子应用内独立。
而且它实际实现了类似js原型链的继承机制,在子应用找不到全局值,会到父应用找。可以实现在主框架上加载umd模块;
局限性分析:需要抛弃IE浏览器;都氚云3.0了,还考虑什么IE!?
TIP
结论:好东西,必用!
# 集成方式
- [ ] 构建时加载
- [x] 运行时加载
组内建议运行时加载,WL建议构建时加载。但我们坚持运行时加载。 原因:构建时加载,又回到了原始的基于构建集成的开发模式,没有做到真正的独立。而且会导致代码与构建过程或构建工具耦合。WL担心的“运行时加载,容易得不到测试的问题”,会有其他的手段解决。
参考qiankun团队的分析:
TIP
结论: 运行时加载, 必用!
# App Entry
- [ ] JS Entry
- [x] HTML Entry
通过fetch
获取html内容,直接插入到浏览器DOM中渲染。可使用import-html-entry
库来加载;
而且可以做到一定的样式隔离作用;
局限性分析:HTMLEntry 需要多一次请求来拉取html内容
参考qiankun团队的分析:
TIP
结论: HTML Entry 好东西,必用!
在实际应用中,也会发现HTML Entry的一些问题,后文会提到
# 样式隔离
有以下两种方案:
- [ ] Shadow dom方案
- [x] 人为规范及约定,BEM / CSS Modules
其次,上文提到,HTML Entry的加载方式有一定样式隔离作用;
Shadow DOM是好东西,但是只用来做样式隔离,还存在一些问题:
- 无法抽离公共样式,真的就完全隔离了,无法灵活处理;
- 一些对外部节点的处理的兼容。比如 sub-app 里调用了 antd modal 组件,由于 modal 是动态挂载到 document.body 的,而由于 Shadow DOM 的特性 antd 的样式只会在 shadow 这个作用域下生效,结果就是弹出框无法应用到 antd 的样式。
但是人为的约定和规范也不是最佳方案,所以这个问题没有最优解,只有权衡;
结论:Shadow DOM 利弊权衡之下,选择人为规范;继续关注研究其他方案;
# 跨模块通信
开放两种跨模块通信机制:
# 全局状态管理(GlobalState)
基于MobX实现
# 全局事件管理(EventBus)
中规中矩的eventbus
详细介绍请看:跨模块解决方案
# 公共依赖的处理
# 加载方式
对于公共依赖的处理,无非以下三种方案;
# npm模块加载
通过npm模块引入; 优点是依赖加载更合理,并可配置按需加载, 缺点是子应用之间,重复的模块打包会有重复;
# 外部cdn加载
将依赖打包成umd模块,通过外部cdn加载进来; 优点是抽离公共代码,减少重复; 缺点是会影响首屏加载资源,可能会出现多余的代码;
# import-maps规范
使用SystemJS库,实现遵循import-maps规范的加载方式; 优点是可以完全自定义化加载,标准规范的加载方式;依赖可复用,可按需加载,可发布外部cdn; 缺点是对SystemJS库的依赖,以及文件的碎片化,没有捆绑加载也不是件好事;
# 加载策略
# 基础框架采用外部cdn加载
vue
、vuex
、vue-router
、lodash
、single-spa
等基础框架采用外部cdn加载
# 组件库采用npm模块加载
以下组件库保持在npm中按需加载
lodash
@h3/antd-vue
@h3/awesome-ui
@h3yun-shared/packages
@h3yun-shared/utils
@h3yun-shared/library
@h3yun-shared/const
# 复合组件import-maps加载
复合组件调用SystemJS加载
# 项目模板
模板是用于快速创建项目使用,集成于脚手架和技术管理平台中; 四种模板:
模板领域 | 模板名字 |
---|---|
主框架模板 | spa-root-template |
子应用模板 | spa-module-template |
复合组件模板 | spa-package-template |
# 静态库管理(static-library)
(未完待续)
以下是新版本处理方案
# 框架类
bundle模块名 | 内部模块 | 描述 |
---|---|---|
bundle | vue, vuex, vue-router, axios,vue-class-component, | |
vue-property-decorator | 氚云基础框架,捆绑vue生态及axios加载器 | |
vuebundle | vue, vuex, vue-router | vue框架 |
h3yun-spa | @h3yun-spa/core, |
@h3yun-spa/global-provider, single-spa, SystemJS | 微前端主框架依赖库 |
# 工具类
bundle模块名 | 内部模块 | 描述 |
---|---|---|
moment | moment | moment库 |
sentry | sentry/brower, sentry/intergrations | sentry异常日志系统SDK |
jquery | jquery | jquery库,用于氚云2.0,3.0不考虑 |
bootstrap | bootstrap | bootstrap库,用于氚云2.0,3.0不考虑 |
# 公共业务组件库
详见:模块拆分