微前端交流
什么是微前端
微前端不是一种技术语言,而是一种架构方案,技术手段或者说是策略。
微前端这个名字以及理念借鉴了微服务的。
微前端可以将一个庞大的系统拆分为多个可以独立开发,独立运行,独立部署的小型应用。
微前端有什么特点
- 技术无关 主框架不限制接入的子应用技术框架
- 独立开发部署 各个子应用可以完全分离,单独部署,互不依赖
- 增量升级 当一个系统太过庞大,一次性进行技术架构升级过于麻烦,成本太高,而微前端恰恰可以实现渐进式升级
- 独立运行 各个子应用之间运行互不依赖,一个子应用服务挂了,不影响系统其他子应用的运行
目前的微前端框架或者方案有哪些
- iframe: 简单且粗暴
- single-spa: 通过路由劫持的方式来做子应用的切换,目前实现微前端的主流方案,可以做二次开发。
优点:- 可以自定义加载哪些子应用
- 可以通过路由切换子应用
缺点:- 主子应用样式冲突,js冲突
- 主应用必须手动加载子应用打包好的资源文件,很麻烦
- qiankun: 阿里基于single-spa做的二次封装,解决了single-spa的痛点问题。
优点:- 阿里团队开发,质量有保证
- 提供了简单易用的API
- 官方文档比较丰富,资料较多
- 提供了沙箱模式,可以解决上面的样式,js冲突问题
- 资源预加载,可以提前加载未运行的子应用静态资源,加快子应用之间的切换速度
缺点:- 只能解决子应用之间的样式污染问题,不能解决子应用污染主应用的样式问题
- 不支持Vite,因为qiankun使用的是import-html-entry来获取静态资源,通过eval来执行这些js,而vite的js type是module的,所以eval执行时,import/export会报错的。
- micro-app: 京东研发团队开发的,没有使用路由劫持,而是借鉴WebComponents的思想,实现微前端组件化渲染。(为什么没使用这个,因为没人接触过)
背景
项目组要基于老的恒丰法律系统推出产品,此前的恒丰法律为前后端不分离的形式,每推广一个客户就需要拷贝一份代码工程,进行新功能开发;同时产品化进行升级需要维护多套代码。
事业群要求产品化要达到的目标:
- 产品化项目可以单独运行及部署
- 产品化和定制化不允许是同一个工程
基于此目标,法律产品化决定采用微前端的模式进行改造。
qiankun 2.7.4
前后端分离拆分
将jquery项目拆分出去:
使用webpack打包, webpack-dev-server启动项目,方便后续es6语法的使用,以及前端项目的单独启动运行。
微前端改造
一、工程拆分
主应用(基座)、子应用
如何拆分主应用、子应用?
主应用(基座):顾名思义,基座就是负责最基本的东西。 页面框架、路由分发、菜单、公共组件、公共样式、子应用的配置等。
子应用:具体的业务功能,可以按照大模块拆分,具体粒度可以根据自己的项目定。
我们是如何拆分的呢?
主应用: 页面框架及菜单(菜单是后端返回的,根据返回的值进行菜单渲染。同时系统维护里面有配套的菜单配置功能)、路由分发、子应用配置。
菜单配置.png
jquery子应用: 法律系统原有的业务功能, 可单独启动。
vue子应用1: 添加到产品化的新功能, 可单独启动。
vue子应用2: 添加到定制化的新功能,替换产品化的原有功能, 可单独启动。
项目结构.png
[图片上传中...(主应用别名.png-75f703-1688436671028-0)]
各个子应用都可以单独启动,如何判断是否是通过微前端启动的?
官方: window.__POWERED_BY_QIANKUN__ (jquery子应用加载之后,此值就变为了undefined,不知道是否为jquery项目的原因,关闭沙箱之后,便可以获取到此值)
其他: 可以通过路由或者hash值判断
如何匹配子应用的?
子应用的匹配是根据路由或者hash值匹配的(hash或者history)
hash:
publicPath和hash前缀一致,都要有(publicPath为nginx拦截提供支持,同时jQuery项目html文件中请求的js和css等静态资源也需要根据publicPath去请求)。
history:
publicPath和路由base前缀不能一样,否则在子应用页面刷新就会直接运行子应用,不会通过主应用激活子应用。
如何在定制化中替换原有产品化功能的?
如果是菜单对应的功能,可以直接在菜单配置中修改对应的路由即可。
如果是页面中某个按钮点击,跳转到新页面,则需要配置,在路由跳转时,根据配置进行跳转。
我们这里比较粗暴,直接在定制化项目的public文件夹下建了js文件作为定制化配置文件,将需要替换的路由挂到了window下。(存在安全隐患,需要加密)
自定义的配置文件.png
二、主子应用通信
官方: props(主传子),globalState(3版本不在支持)
挂到window
webpack5: 热插拔 ModuleFederationPlugin
主应用globalState.png
props传值.png
子应用获取存储.png
公共组件/方法如何处理
- 作为公共组件库提供出去,npm 依赖管理
-
使用git仓库的submodule, 将公共代码单独拿到一个代码仓,只放公共代码即可。 在需要使用的项目中使用git submodule将公共代码作为子工程引入进来。 问题: 各个子应用都可以随意修改公共代码。看代码(feature-git-submodule分支)
gitsubmoudle使用方式.png
submodule目录结构.png
- 在主应用中引用子应用的代码,挂到window上。在子应用中使用window。需要注意各个子应用的根路径别名要不同,同时需要在主应用中配置别名。 看代码(feature-common-components分支)
主应用别名.png
子应用别名.png
组件挂载到window.png
-
webpack5 ModuleFederationPlugin热插拔(不能使用splitChunks) 看代码(feature-webpack5分支)
热插拔remote方.png
热插拔使用方.png











网友评论