09-面试讲解
# 微前端解决巨石应用
# 面试讲解
微前端不是特指某一项技术,而是一种理想与架构模式。
由于微前端的库各自实现不同,在面试的时候选择一种常见的微前端库进行主要描述即可,这里选择qiankun
# 知识点图谱
# 难点描述
**模拟问题:**我看到你这个项目里面,用到了微前端,出于什么考虑,你们这个项目需要用到微前端呢?
问题分析:
可能问题稍有区别,不过如果面试官问到微前端的问题,不管面试官怎么问,问题是什么,我们的回答一定是先解释清楚下面几个问题:
- 这个项目为什么要使用微前端(重点描述)
- 为什么不考虑比较简单的实现,而是用微前端库进行处理(埋钩子)
- 对于现有常用微前端库的选择,以及选择qiankun出现的问题(埋钩子)
- 最后使用微前端的结果如何?是否达到预期目的?
第一个问题,主要是展示自己对于微前端架构的思考和理解,拔高自己在面试官心中的印象
第二三个统统都是埋钩子,可以展示自己对于微前端,乃至整个前端知识的了解,自己解决问题的能力等等,诱导面试官顺着你埋下的钩子往下追问。
最后的问题,微前端使用之后的结果。追问面试官是否需要细说
参考答案:
首先来说,这个项目是公司的几年前的B端项目,而且现在一直在维护,不过维护的成本越来越高,很多地方,不论是客户也好,还是我们开发者自己都比较的不满意。后台的代码量越来越臃肿。所以公司当时决定对整个项目的架构进行升级。不过公司的要求是,遗产代码能平滑的迁移,不能影响客户的使用,而且最好还能确保若干年后还能用上时下热门的技术栈。
而且,我们这个项目,作为B端项目来说,业务边界比较明确,虽然项目体量庞大,但是业务之间耦合度不算太高。而且项目持续的年限也比较久了,有些业务的技术栈比较老旧了,扩展起来比较的困难,第三方库这些都不敢轻易的更换或者升级,所以公司要求升级,基本上也是到了不得不这么做的地步了。
(
上面的描述,基本上就是在阐述使用微前端的核心原则和适配原则,当然,如果按照书本的说法:
1、技术栈无关
2、具备独立开发、独立部署
3、增量扩展迁移
4、业务隔离,单独决策
这么说出来就太刻意了,而且也谈到了微前端改造的适配原则:
1、动力:公司要求要改,不得不改了
2、系统及组织架构上:业务边界明确,业务耦合度不高
3、增量升级:可以进行渐进式升级
4、B端项目:一般ToC 业务活得过 3 年以上很少,只有ToB的项目,类似于管理/产品的控制台才有较长的寿命
)
(继续)
当然,刚开始我们也先考虑的并不是直接使用市面上的微前端框架方案,而是直接用iframe(埋钩子,可能会诱导面试官追问:为什么会直接先考虑iframe,iframe有哪些问题),但是考虑到业务中的需要,以及后续的升级问题,还是排除了这个方案。
市面上常用的微前端库,我都做了比较详细的对比,比如
qiankun
,micro-app
,无界
(埋钩子,可能会诱导面试官追问:这几个框架都有什么优缺点呢?)等等。其实吧,都有各自的优缺点,但是毕竟前端世界中没有银弹,特别是微前端。毕竟就算是使用iframe也不是不能用。最后还是考虑选用qiankun
。而且在使用的过程中,我们确实也遇到了很多问题,不过对
qiankun
的原理掌握的比较清楚之后(埋钩子,引导面试官提问:qiankun有哪些原理性问题),这些问题总归也可以解决。当然最难的倒不是这些技术问题,而是最开始的时候,我们这个项目该怎么进行拆分,刚开始没想太多,走了很多弯路,最后化繁为简,反而轻松不少(埋钩子,提升逼格的问题,就算面试官最后不追问,在面试官想不到问题的时候,最好也要主动说出来)
**(最后结果)**经过微前端的拆分,在开发侧,基本做到了子项目的独立开发,独立发布,当然了,需要通过主项目联调的内容刚刚开始还存在一些问题,不过在子项目业务,以及范围完全理清之后,也非常的顺畅了(埋钩子:引导面试官追问)。在用户端也保证了项目逐步的替换,不影响用户的使用感受。在后期做增量开发的时候整个流程也非常的顺畅。
**(最后追问:)**基本上就这样的情况,看面试官您还有哪些细节想了解的?我再详细说一下?
# 知识点叙述
# 1、iframe(nginx路由转发)
**模拟问题:**iframe(nginx路由转发)有什么问题,展开来说一说。
问题分析
如果前面的钩子引起了面试官的兴趣,他让你把这个问题展开来讲一讲,那么就开始叙述每个知识点的相关描述。注意当你描述完一个知识点后,稍微和面试官互动一下,不然就变成了你一个人在那儿长篇大论的讲。
这个问题,我们在技术讲解的文档中已经提到过,这里就不在赘述...
另外,如果使用iframe和路由转发的方案,如果还要做前端监控等操作,就只能在各自的项目中进行处理,这样会比较的麻烦,后续也会有改造成本
# 2、子应用拆分
**模拟问题:**你们这个项目要把大应用拆分成各自的子项目,在拆分的时候有没有考虑什么拆分规则呢?
问题分析
这个问题如果是懂行的面试官,可能是一开始就会问,当然也有可能不问。但是无论怎么样,就算不问这个问题,我们自己一定要说,这是展示自己架构业务思维的问题。比技术问题有逼格的多,也是给面试官留下深刻印象的问题。
参考答案:
子应用的拆分当然首先考虑的就是按照业务进行拆分嘛。但是当中其实有很多细节我们需要考虑。总的来说,把持住几点规则就好办:
首先,保持核心业务的独立性,把无关的子业务拆分解耦
另外,业务关联紧密的功能单元应该做成一个子应用、反之关联不紧密的可以考虑拆分成多个微应用,判断业务关联是否紧密的标准,其实很简单,就是看这个子应用与其他子应用是否有频繁的通信需求。
当然还要看页面结构,如果结构不清晰,业务有交叉,就算是单独的业务,还是做成一个子应用比较好。不过这个还是要分情况,我们当时也有争论,是不是还要应该尽量考虑未来场景?
最终我们还是考虑把持度的问题,一开始不用拆分的太细,不要盲目细致拆分,未来有需要,再进行拆分处理。可以先粗粒度划分,然后随着需求的发展,逐步拆分
反正是拆还是合,总归还是和程序设计原则一样的:拆的是系统复杂度,合的是系统复用度 核心原则:高内聚,低耦合
# 3、常见微前端库的优缺点
**模拟问题:**我看你说了解过几种不同的微前端库,你能说说他们有什么区别和各自的优缺点吗?
问题分析
这个问题的提出,基本是是我们上面钩子的引导,无非给面试官展示两点:
1、你对技术的热爱,渴求
2、技术选型的考虑
因此在说的时候,可以加上你对技术原理的了解,当然,选择一种重点说明就行了,其他的了解过即可
当然具体的一些区别,在上一节的技术细节中有提到。
参考答案:
要说区别和优缺点,肯定要从这几个库的原理实现层面上来说。
基本上qiankun,micro-app,无界在子应用加载,渲染,JS沙箱隔离,CSS隔离,应用通信上面都有区别,但是其实也都有相似之处。
比如在加载和渲染上,
qiankun
使用的是路由和HTML Entry
,而micro-app
的渲染说白了还是HTML Entry
那一套,只不过又加入了Web Components
,不用再去劫持路由了而已。
HTML Entry
其实就是借助webpack在应用打包时候的特点,读取打包之后的HTML文件中的内容,将HTML文件中的js和css分别提取出来,然后通过分析处理,再将这里面的内容放到到主应用当中。当然JS沙箱主要是Proxy沙箱和iframe沙箱的区别,
无界
使用的是iframe沙箱CSS隔离主要也是工程化方案和shadow dom,
无界
采用的是基于iframe劫持和shadow dom应用通信
qiankun
采用的是props属性传递的方式,micro-app
借助了WebComponent
和浏览器的CustomEvent
,无界
则是基于iframe同域下的window去中心化的eventBus优缺点的话,其实没有完美的方案,主要还是看我们自己的需求:
如果基于上手和接入成本,
无界
和micro-app
上手简单快速,不过无界
对于内存消耗比较大,而且效率最低如果基于兼容性,qiankun要好一些,不过接入成本要大一些,而且子应用不支持使用vite
# 4、qiankun的原理问题
**模拟问题:**qiankun支持子项目是vite吗?qiankun支持keep-alive吗,如果不支持,有没有自己实现的思路?
问题分析
有时候可能会直接了当的问你一些原理问题,比如:说说qiankun的资源加载机制(import-html-entry)
当然有时候,可能会像上面以具体场景问题来问你。
参考答案:
qiankun支持子项目是vite吗?
不支持,因为
qiankun
是HTML Entry
的机制,说白了,就是利用webpack打包的机制,将子应用的HTML内容直接读取到主应用中来,再进行处理。而vite本身是ES Module的,也就是说 vite 构建的 js 内容必须在type=module
的 script 里面,这会导致qiankun其实拿不到子应用JS里面的内容执行。虽然市面上有一些基于qiankun子应用可以使用vite的插件,但是我们并不建议使用,一是这样做有很大的隐患,肯定需要修改很多内容。二是我们的项目本身就是做拆分,因此在打包工具上做了统一。
虽然微前端不限制技术手段,但是规范化不做统一处理,那么我们的项目只会从一个问题,变成另外一个更大的问题
qiankun支持keep-alive吗,如果不支持,有没有自己实现的思路?
在
qiankun
中,实现keep-alive
的需求有一定的挑战性。这是因为qiankun
的设计理念是在子应用卸载时,将环境还原到子应用加载前的状态,以防止子应用对全局环境造成污染。这种设计理念与keep-alive
的需求是相悖的,因为keep-alive
需要保留子应用的状态,而不是在子应用卸载时将其状态清除我们当时也出现了这种需求,我说一下我们的处理办法:
qiankun
中还提供了手动加载函数loadMicroApp
,我们可以获取当前激活子应用的对象。所以,我们要实现keep-alive
,就需要借助这个函数另外,我们要实现
keep-alive
实际上,我们只需要缓存子应用的具体页面就行,而子应用如果是vue的项目,是可以有自己的keep-alive
对当前路由进行缓存的。所以,要实现keep-alive
效果,我们就需要两步1、缓存子应用对象
2、子应用自身实现
keep-alive
效果
当然,具体微前端中的问题千奇百怪,关于qiankun
中常见的一些问题,可以查看qiankun
官网的常见问题 (opens new window)
# 5、微前端打包发布问题
**模拟问题:**你将一个项目通过微前端拆分成了多个项目之后,在项目打包发布,或者启动调试的时候有没有遇到问题?
问题分析
这其实也是一个具体场景题,这也是有经验的面试官在给我们挖坑,看我们有没有具体的微前端经验,我们尽量说的轻松简单就好,毕竟每个公司微前端的处理方式都有可能不一样
参考答案:
这确实是会遇到问题的,比如你说的打包发布的问题,这其实也是前面我一直说的微前端业务场景需要隔离的原因之一,如果主项目和各个子项目之间隔离,耦合度不高,本地开发都只关注自己项目的业务,那就基本没有什么问题。
至于启动调试也是一个坑点,毕竟有主项目和多个子项目,主项目下要调试那就必须要启动所有子项目,所以我们一开始的方案也是希望实现按需启动子项目。但是后面发现这其实是个伪需求,毕竟我们业务场景一开始就划分的比较好,耦合度不高,各个子项目单独调试好就行。主项目主要目的还是路由和通信这一块。我们把需要频繁通信的业务直接合成了一个子项目,尽量的去减少通信。不增加微前端整个架构的复杂度。所以最后还是不整费力不讨好的事情,增加开发工作量。还是用的最简单的方案,直接用了
npm-run-all
插件,启动主项目的时候直接启动相关子项目就行。
# 6、公共依赖
模拟问题:如果主子应用使用的是相同的库或者包,微前端怎么解决重复加载导致资源浪费的问题?
问题分析
这其实也是一个具体场景题,首先你要知道面试官问的是什么意思:
如果主子应用使用的是相同的库或者包 (
vue、axios、vue-router、element
等), 一个项目使用了之后,另一个项目使用不再重复加载,可以直接复用这个文件参考答案:
不要共享运行时,即便所有的团队都是用同一个框架。- [微前端](https://micro-frontends.org/)
虽然共享依赖并不建议,但如果你真的有这个需求,你可以在微应用中将公共依赖配置成
externals
,然后在主应用中导入这些公共依赖。(当然如果面试官要追问:具体怎么操作
Externals
,你简单介绍一下Externals
的原理就行了)无非就是
qiankun
将子项目的外链script
标签,内容请求到之后,会记录到一个全局变量中,下次再次使用,他会先从这个全局变量中取。这样就会实现内容的复用,只要保证两个链接的url
一致即可。为了节约那么一点打包空间,个人非常不建议这么做,这样子应用不能很方便的独立运行,这和微前端的理念是违背冲突的,另外由于关键对象都挂载到了window上,很容易引起子应用和主应用之间的冲突