场景
- 一个在某某行业为运营商提供服务的科技公司
- 首先会开发一个关于机器各种功能的运营系统(机器中心)
- next,要为供应商提供数据分析的系统(数据中心)
- next,为运营商提供各种促销活动(营销中心)
- …. (业务更多,需要的管理系统也很多)
短期之内全部用一个前端项目开发,没有问题。但是当业务量不断扩展,从开发到用户会有各种影响(当然分多个项目也没问题,但是用户需要记住N个链接)
这么就会出现问题
开发:
- 代码量大,打包慢,包体积大,时间越长
- 整个系统的ui主题不好管理
- 每一次迭代上线,影响面大
- 代码耦合混乱,不敢动,牵一发何止动全身
用户:访问会越来越慢,很容易受到开发上线影响的自己的功能,主题千年不变等等。
思考
如何将一个巨石的管理系统改造拆分(各个中心的模块下面还有几十个菜单)
微前端是个啥
将前端应用分解成一些更小、更简单的能够独立开发,测试、部署的小块,而在用户看来仍然是内聚的单个产品。
微前端的三个要素,即:独立运行、独立开发(与技术栈无关,应用之间不应该有任何直接或间接的技术栈、依赖、以及实现上的耦合)、独立部署
优势
- 复杂度可控: 每一个UI业务模块可以由独立的前端团队开发,避免代码巨无霸,便于维护与开发效率。
- 独立部署: 每一个模块可单独部署
- 技术选型灵活: 在同一项目下可以使用如今市面上所有前端技术栈,也包括未来的前端技术栈。
- 容错: 单个模块发生错误,不影响全局。
- 扩展: 每一个服务可以独立横向扩展以满足业务伸缩性,与资源的不必要消耗;
希望改造成这样
对外,看上去是一个系统。对内又可以分多个web项目
常见的实现方式
- 传统iframe
- 优点:应用之间自带沙箱隔离
- 缺点:重复加载脚本和样式
- 需要解决的问题:
- 布局问题:iframe必须给一个指定的高度,否则会塌陷
- 弹窗及遮罩层问题:只能在iframe范围内垂直水平居中,没法在整个页面垂直水平居中(可使用全局的弹窗)
- 浏览器前进/后退问题:iframe页面刷新会重置(比如说从列表页跳转到详情页,然后刷新,会返回到列表页),因为浏览器的地址栏没有变化(push基层进行路由跳转)
- 每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程。
- 运行时组合(每个子应用独立构建,运行时由主应用负责应用管理,加载,启动,卸载,通信机制)
- 优点:具有良好的体验,真正的独立开发,独立部署
- 缺点:复杂,需要设计加载,通信机制,无法做到彻底隔离(基于 shadow DOM 的样式可以实现样式隔离,比如qiankun.js),需要解决依赖冲突,样式冲突问题
-
Web Components
浏览器的原生组件,相比第三方框架,原生组件简单直接,符合直觉,不用加载任何外部模块,代码量小(现在流行的React,Vue都是组件框架)
每个子应用需要使用 Web Components 技术编写组件或者使用框架生成
- 优点:面向未来的技术
- 缺点:重构代价很大,所有的代码需要用web Components重写
//MDN地址
https://developer.mozilla.org/zh-CN/docs/Web/Web_Components
复制代码
目前国内关注度比较高的技术
目前使用比较多的是运行时组合的方案。关注度和成熟度最高的应该就是 single-spa。还有国内关注度很高的蚂蚁金融的框架qiankun
qiankun 是一个生产可用的微前端框架,它基于 single-spa,具备 js 沙箱、样式隔离、HTML Loader、预加载 等微前端系统所需的能力。qiankun 可以用于任意 js 框架,微应用接入像嵌入一个 iframe 系统一样简单(想知道更多请去官网)
说了这么多,下面才是重点
当前有个项目遇到如下瓶颈
- 第三方js混乱(jquery,react,vue,angular一锅乱炖)
- 大多都是jquery代码,代码量大,阅读困难
- 业务特别多,页面有百来个吧
- 等等…..
(当然,不可否定,在当时,这是一个架构很好的项目)
优化目标
在不影响原来的项目基础的情况下优化项目,以最小改动,使之既能继承原有的能力,又符合现在的开发习惯和技术方向(注入微服务的思想)
解决方法
针对这个项目iframe方案是接入成本最廉价的选择,同时也支持通过possMassage实现父子之间的通讯。而且,对于陈年已久的Jquery多页面的老项目,qiankun对多页应用没有很好的解决办法。每个页面都去修改,成本很大也很麻烦,但是使用 iframe 嵌入这些老项目就比较方便。
(新建两个子项目vue/react各一个,在原来的架构下,开发访问)
需要解决的问题:
- 使用iframe,并且路由中以 “#/iframe” 开头即可访问并隐藏其他的内容,分开iframe与原有的内容的并且通过显示隐藏进行切换
- 解决访问关系,即本地开发和线上访问(线上访问打包后的内容,线下访问本地能热更新代码)本地访问地址(自动截取iframe后面的url并访问)
//本地
http://localhost:8080/main/index.html/#/iframe/http://localhost:3001
//线上访问地址(localhost改为ip地址):
http://localhost:8080/main/index.html/#/iframe/test/dist/index.html
复制代码
-
配置代理解决本地访问跨域
-
由于原来的项目,属于直接访问文件,所以子项目的打包需配置相对路径
因为dist文件是需要放在服务器上运行的,资源默认放在根目录下。打开index.html可以发现,css和js文件的引用使用的是绝对路径。但对本地磁盘来说,/指向磁盘根目录,所以会找不到引用的文件。需修改项目的publicPath为’./’(需要看具体的项目)
-
由基层传递菜单给子项目(由项目状况决定,也可以单独控制)
-
API请求
本地请求启动代理即可(需要注意cookie情况)
-
由于iframe的缺陷,使用弹窗及遮罩层问题(基层提供全屏方案,即子项目调用基层的全屏的弹窗)
-
基层架构与子项目之间的数据交流
为符合线上线下都能使用(线下存在同源问题),使用postMessage实现,然后项目内部使用公共bus,传播基层传递过来的消息(依据项目的技术情况)
有个注意点:在react项目中可以等待基层将所有的信息准备完毕并传递给子项目之后再渲染主要内容。但是在vue中延迟挂载app.mount(‘#app’)会报错。所以使用公共bus将基层信息,传播给子项目
运行方式
本地开发运行两个项目,一个是基层的一个是独立的项目
最后
最后和某位大佬有个讨论点,就是iframe做微前端不好。因为看了why not ifram这篇文章。但个人觉得,用哪个还是要看实际情况,针对这次项目优化,你的目标是啥。qiankun.js就牛了?是的蛮牛的,但是不能因为iframe比较上年纪,就嫌弃。。。。peace and love~
记得给我点赞????