目录
写在前面
本文所有技术实现的相关代码都已开源,想clone或者fork,请直接拉到文章末尾。
另外,技术实现借鉴了国内开源软件 kubevela,非常感谢kubevela的各位大佬能开源质量如此之高的代码。且因为本人是行业菜鸡,代码中如有语法错误或其他问题,请在评论区指正,感谢各位。
一、微前端相关知识
微前端(Micro Frontends)是一种前端架构的模式,旨在将大型前端应用拆分为多个独立的、可组合的小型前端模块。这些模块可以由不同的团队独立开发、部署和维护,最终在用户界面中无缝集成。微前端的核心思想类似于后端的微服务架构,通过模块化的方式降低系统复杂性,提高开发效率和扩展性。
(一)概念
-
独立部署:每个前端模块可以独立开发和部署,不依赖于其他模块。各个模块之间通过预定义的接口进行通信。
-
技术无关:不同的前端模块可以使用不同的技术栈(如React、Vue、Angular等),这使得团队能够根据具体需求和技术栈选择合适的工具。
-
团队独立:微前端允许不同的团队负责不同的模块,降低了团队间的耦合度。每个团队可以独立管理其代码库、开发流程和发布节奏。
-
界面组合:微前端架构通过组合不同的模块构建完整的用户界面。这可以通过在浏览器中动态加载不同的模块来实现,通常使用iframe、模块联邦(Module Federation)或自定义加载逻辑。
-
渐进迁移:微前端使得大型遗留系统可以逐步迁移到新技术中,减少一次性重构的风险和成本。
(二) 优势
- 扩展性强:每个模块独立开发和部署,能够快速迭代和扩展功能。
- 灵活性高:不同模块可以选择不同的技术和工具,而不影响整个系统。
- 提高团队效率:独立团队可以并行开发,减少依赖和协调。
(三) 缺点
- 性能问题:由于多个模块的组合可能导致资源加载和渲染效率问题,需要特别注意优化。
- 共享状态和通信:不同模块间的数据共享和通信需要标准化和规范化,避免耦合过高。
- 样式和UI一致性:虽然模块独立开发,但最终呈现给用户的界面需要保持一致的用户体验和样式规范。
(四)应用场景
- 随着技术的发展,前端应用可能需要从旧的技术栈迁移到新的技术栈。然而,对于大型应用,一次性迁移的风险和成本往往较高。微前端使得可以逐步迁移——某些模块可以采用新的技术栈,而其他部分保持不变。这种方式降低了技术迁移的风险和成本。
- 微前端允许这些团队各自独立开发、部署和维护自己的模块,而不影响其他团队。这种方式有助于减少依赖、加快开发节奏,并使应用更加易于扩展。
(五)现有框架
1. qiankun
qiankun 是一个基于 single-spa 的微前端框架,专注于子应用的加载、沙箱隔离以及跨应用的通信管理。qiankun 提供了开箱即用的解决方案来管理多个微前端应用,并在容器应用中将它们集成到一起。它的插件化功能可以帮助不同技术栈的子应用共存。
官网地址:
qiankun - qiankunhttps://qiankun.umijs.org/zh
2. single-spa
single-spa 是一个流行的微前端框架,它允许多个前端框架(如 React、Vue、Angular)在同一个应用中共存,并实现独立加载和渲染。single-spa 的插件化机制允许开发者将每个子应用打包成独立的模块,单独部署和运行。
官网地址:
3. SystemJS
SystemJS 是一种模块加载器,通常用于微前端架构中实现动态模块加载。通过 SystemJS,应用可以在运行时按需加载不同的子应用或插件,而不是在构建时打包所有内容。它常与 single-spa 等微前端框架一起使用。
GitHub地址:
二、需求分析
年初,公司产品经理提出了一个概念,叫js热加载热更新,需要什么js文件就动态加载什么js文件。因为目前公司的产品,有两个代码仓库,一个用于企业版,一个用于做开源版。开源版的核心代码与企业版的核心代码无差别,但在定制化和某些功能的支持上,企业版更占据优势。但是,同时维护两个仓库的很多分支又比较耗费人力物力,无论是企业功能下方开源,还是开源功能合并企业都比较繁琐,且合并过程中也有一些风险,因此就想到用这种热更新的模式,开源版与企业版的代码一致,但是企业版可以通过js热加载的方式动态导入一些前端页面或者功能用于实现和开源版的差异化,但这部分企业版的功能又不能放在开源代码中,因为直接放的话,有懂前端的开源用户就可以很轻松的破解代码了,因此想到了动态加载js这个方法来注入前端代码,以防止可以很轻易的就破解代码。
在经历调研后,发现微前端这个东西貌似很符合我们的需求,但是因为主项目的版本过于老旧(umi 2.X),并不能适配当下主流的微前端插件,而且有些定制化的需求跟主流微前端的插件又不相吻合,所以,在这个背景之下,我参考借鉴了 kubevela 的插件实现方式,最终使用SystemJS实现了插件功能。
kubevela项目地址:
https://github.com/kubevela/kubevelahttps://github.com/kubevela/kubevela
三、流程概览
(一)子项目改造
子项目的改造就一个重点----打包。因为涉及到很多东西,比如插件元数据设置与拷贝,版本更新,数据传输,以及webpack5打包后的文件类型等,都有许多讲究。
(二)npm包
制作插件需要一个npm依赖包作为数据传递的中转站,子项目打包后会返回一个函数,这个函数在主项目中也有引用,通过system.js导入子项目后,在主项目调用该函数,即可获取子项目中传入的数据,也就是react的组件。从而串通整个流程。
(三)system.js插件封装
当你完成子项目与npm后,就需要封装system.js用来将子项目打包后的代码动态导入到主项目里。
(四)主项目改造
主项目的改动其实就比较小了,安装system.js与自己制作的npm依赖,再划定一些路由用于渲染该插件,主项目的使命就算完成了。
四、子项目改造
(一)子项目创建
这一步很好理解,使用脚手架创建一个react应用,然后再针对于react应用进行webpack5的打包改造。或者直接从github上下载一个使用webpack5打包的react模板。
package.json文件,这里面有我所有依赖的版本信息,需要的可自行查阅。
{
"name": "plugin-template",
"version": "1.0.0",
"description": "插件体系模板文件",
"scripts": {
"dev": "cross-env NODE_ENV=development webpack serve --config ./build/webpack.dev.config.js --open",
"build": "cross-env NODE_ENV=production webpack --config ./build/webpack.prod.config.js",
"build:report": "cross-env NODE_ENV=production REPORT=true webpack --config ./build/webpack.prod.config.js",
"eslint:init": "eslint --init",
"prepare": "husky install",
"lint-staged": "lint-staged",
"commitlint": "commitlint -e",
"eslint:fix": "eslint --ext .js,.vue --fix src"
},
"keywords": [],
"author": "xuzhonglin12138",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.15.5",
"@babel/plugin-transform-runtime": "^7.15.0",
"@babel/preset-env&#