作者|vivo互联网前端团队-蒋作涵一、背景VAPD是一款专为团队协作办公场景打造的项目管理工具。它实践敏捷开发和持续交付。以“项目”为核心,整合需求、任务、缺陷等应用,采用敏捷迭代和小步骤进行开发和质量跟踪,简化工作流程,帮助团队快速迭代,高效完成产品开发和交付。但在前期,VAPD以“万物皆可配置”的设计理念研发运营了两年。整个前端代码复杂混乱,组件庞大(需要支持多种配置),状态混乱,打包后的前端代码有50M之多。这个项目不可持续,bug多,维护困难,新功能有限。总之,产品不满意,测试不满意,用户不满意。因此,改版是必然的选择,改版的要求并不是为了耽误用户继续使用。需要保证网站的可用和逐步更新,微前端是必然的选择。VAPD改版思路是:使用微前端框架,未改版部分作为子应用存在,继续为用户服务;为项目模块制定系统应用,并逐一修改,降低项目复杂度;逐渐放弃旧的项目代码并将功能转移到新的项目代码中。在项目中,提高项目的整体性能,提高代码的可维护性。2.什么是微前端构建现代Web应用程序的技术、策略和秘诀,多个团队可以独立发布功能。——微前端。方法策略。微前端将微服务的概念应用到浏览器端,即把单页面前端应用从单一的单一应用转变为将多个小前端应用聚合为一个的应用,每个前端-终端应用独立开发部署。微前端架构旨在解决由于参与人员和团队在较长时间跨度内的增加和变化,导致单体应用从普通应用演化为FrontendMonolith的问题。无法维护的问题。这种类型的问题在企业网络应用程序中尤为常见。目前最著名的微前端是阿里的qiankun,它是一个基于single-spa的微前端实现库,旨在帮助大家更轻松无痛地搭建一个生产就绪的微前端架构系统。但是在试用了qiankun之后发现qiankun的npm包经常滞后于qiankun的源码。部分问题已解决,但仍需等待发布;第一次加载时子应用页面抖动;子应用更新后报ChunkLoadError。同时,它也有微前端框架普遍存在的性能问题和冲突:1.加载慢。基本上所有的微前端框架都需要先加载父框架,再加载子应用,必须经历下图所示的流程。整个流程是串行的,同一个流程需要走两次,比普通非微前端框架慢1倍左右,直接影响用户体验。2.切换慢,每次切换都需要重新走流程。要在微前端框架中切换不同的子应用,需要销毁当前的子应用,然后加载其他子应用。子应用需要经历“下载html-->下载javascript文件-->运行javascript代码-->请求服务器端数据-->页面展示”的全过程,这就造成了微前端框架切换应用程序并不流畅。3.容易出现风格冲突,不同的子应用容易影响。传统微前端框架中的所有子应用程序都在同一个上下文中。如果有全局样式、全局监视器、全局变量,会影响到其他子应用,容易出现样式冲突、内存泄露或不可预知的bug。3、WhyNotIframeiframe最大的特点就是提供了浏览器原生的硬隔离解决方案,所有的样式隔离、JS隔离等问题都可以完美解决。那么为什么不使用iframe呢?qiankun团队也给出了理由:seeWhyNotiframehere。总结一下:url不同步。浏览器刷新iframeurl状态丢失,后退和前进按钮无法使用。UI不同步,DOM结构不共享。想象一下,在屏幕右下角的iframe中有一个带有遮罩层的弹框。同时,我们要求这个弹框显示在浏览器的中央,并且在浏览器调整大小时自动居中。全局上下文完全隔离,内存变量不共享。针对iframe内外系统的通信和数据同步需求,必须将主应用的cookie透传给不同根域名的子应用,以达到避免登录的效果。慢的。每个子应用入口都是一个浏览器上下文重构和资源重新加载的过程。这些问题有的比较容易解决(问题1),有的问题我们可以视而不见(问题4),但是有的问题我们很难解决(问题3)甚至不可能解决(问题2),而这些无法解决的问题会给产品带来非常严重的体验问题,最终导致我们放弃iframe方案。4.Optimus框架设计4.1设计理论基于以上微前端缺陷,设计一个新的微前端框架需要满足以下要求:快速——页面加载速度和应用切换速度是终极追求前端,用户操作的响应速度永远是第一体验。完全隔离——不同的子应用完全隔离,只在子应用项目初始化时设置一次,后续开发和后期维护无需考虑,减少开发的精神负担。4.2架构设计擎天的框架架构分为三层,分别是用户入口(浏览器地址栏)、主应用层和子应用集合层。(1)浏览器(地址栏)是用户的入口。用户通过输入URL进入系统。同时,浏览器地址栏中的URL会根据应用页面发生变化,方便用户复制分享进行二次入口。(2)主应用是Optimus框架的关键部分,主要由以下两部分组成:路由引擎:实现浏览器地址栏与子应用显示隐藏的协同控制,用于控制用户首次访问显示某个应用,当用户切换页面时,需要同步浏览器地址栏(方便用户再次复制进入同一页面),根据需要显示和隐藏子应用到页面URL。数据共享引擎:实现子应用之间的数据共享,保证应用之间数据的统一性,如登录信息、用户信息等,用户在应用中修改共享数据后,会同步到数据共享引擎,然后分发给其他应用程序,以确保共享数据的一致性。(3)子应用集合层该层是系统预先设置的子应用的集合。子应用由全屏iframe加载,同时只有一个子应用可见,其他子应用隐藏。当需要切换应用时,隐藏当前应用,显示需要显示的应用,即时切换。子应用响应擎天的路由引擎和数据共享引擎,实现实时路由同步和数据同步,保证整个微前端项目路由和数据的统一。5、Optimus框架实现Optimus框架突破了iframeUI不同步、URL不同步、数据不共享、加载慢等问题,以iframe作为页面容器实现硬隔离实现子应用之间的即时切换。解决了微前端框架的通病,实现单一应用层面的操作体验。5.1全屏iframe和常用组件解决问题:UI不同步。全屏iframe是指将整个浏览器窗口交给子应用iframe,子应用接管浏览器的所有功能,无论是全局拖拽,全部遮罩,resizie等,让UI不同步的问题将不再存在。但是不同的应用有相同的公共部分,所以需要将公共部分做成一个统一的组件,打入npm包,在各个应用中导入。5.2解决父子应用异步加载问题:加载慢在前端静态页面预留子应用dom节点,如下图,每个div都有唯一的id,代表一个预制的子应用。同时id对应子应用的路由pathname,例如New对应/New/*路由,即所有以New开头的路由都对应id为“New”的子应用。当用户进入页面时,父框架得到浏览器的url和路径名,这样它就知道需要先加载哪个子应用程序。并且直接创建一个iframe,直接挂到对应的dom节点,父应用和子应用异步加载。加载第一个子应用后,开始加载其他子应用并使用display:none将它们隐藏在页面dom结构中。最终的dom节点如下图所示。5.3子应用iframe即时切换解决问题:子应用切换卡顿当用户在多个子应用之间切换时,擎天监听浏览器url地址。如果路径名由/New/*变为/Web/*,则隐藏/New/*对应的子应用iframe,显示/Web/对应的子应用iframe,实现应用的即时切换。用户在可视范围内只能看到一个应用。切换时,只有新建应用隐藏不可见,Web应用页面可见。5.4路由引擎,同步切换方案:URL不同步受vue2中数组方法(如push、shift)响应式处理的启发,擎天专门处理了前端路由框架,重写了vue-router的push和replace等方法,当检测到子应用使用上述方法切换路由时,会同步到父框架进行操作。父子应用简单配置后,父子路由同步就完成了。路由切换分为单应用和多应用路由切换。(1)单应用路由切换单应用子iframe路由切换,比如从/New/b切换到/New/c,具有相同的路径名结构,是单应用路由切换。子应用先切换路由,然后发送syncRoute给父框架,父框架使用replace方法改变浏览器地址栏。具体过程如下图所示。(2)多个应用之间的路由切换,比如从/New/b切换到/Web/c,路径名结构不一致。子应用首先切换路由,然后向父框架发送syncRoute消息。父框架使用replace方法改变浏览器地址栏,隐藏应用A,向子应用B发送消息,子应用B获取消息后修改自己的路由。5.5数据共享解决问题:内存变量不共享。父应用将需要共享的数据放入store,并注册到syncStore。子应用可以通过类似vuex的mapGlobalState方法获取父应用store中的数据。同时,数据是响应式的,数据变化可以触发UI重新渲染。通过mapGlobalMutations获取修改数据的方法可以通过该方法修改父应用的store数据。修改成功后,擎天共享数据引擎会将修改后的数据分发给各个子应用,保证共享数据的一致性。其内部逻辑是:父应用将需要共享的数据放入store,并暴露getTopStore(获取store数据)、syncTopMutation(更新store数据)、syncTopStore(分发store数据)等接口。系统加载时,子应用可以通过getTopStore方法获取store中的数据,赋值给子应用$pstore,从而获得数据响应能力等能力。当子应用需要修改共享数据时,调用syncTopMutation方法进行修改。修改成功后,Optimus通过syncTopStore分发给各个子应用,保证共享数据的一致性。六、总结擎天基于全屏iframe构建公共组件,解决了iframeUI不同步的问题,充分发挥了iframe作为页面容器的优势,实现了异步加载的能力父子应用和子应用的即时切换,从而实现单一应用项目的体验。
