1.背景魔法学校从tob开始。众所周知,tob业务很容易做出巨石应用。这两年,魔法学院发展的很快。我们的一个主要前端项目遇到了瓶颈。然后就是工程太大了。为了降低耦合,加快打包速度,我们选择提出一些功能新建一个项目,然后通过iframe引入到主项目中。虽然解决了项目体积大的问题,但用户体验也相应下降。因为每次用户切换到iframe的tab,不管怎么优化,总会有片刻的白屏。感觉就是两个系统。业务的快速发展迫使我们寻找新的出路——微前端。二、微前端的基本概念1、什么是微前端?当前的趋势是构建功能丰富且功能强大的前端应用程序,称为单页应用程序(SPA)。前端层通常由一个单独的团队开发,随着时间的推移,它会变得更大,更难维护。这就是传说中的FrontendMonolith。微前端背后的想法是将网站或网络应用程序视为功能的集合,每个功能都由一个单独的团队处理。每个团队都有特定的业务专长领域或它关心的任务。在这里,一个团队是跨职能的,它可以端到端地开发它负责的功能,从数据库到用户界面。然而,这个概念并不新鲜,过去它被称为前端集成或垂直系统的独立系统。只是微前端显然是一个更友好、更简洁的术语。2、微前端的优势?复杂度可控:每个UI业务模块由独立的前端团队开发,避免代码巨人,在开发过程中保持高速编译,保持低复杂度,方便维护和开发效率。?独立部署:每个模块可以独立存储和部署,不影响其他模块。?灵活的技术选择:也是最吸引人的地方。现在市面上所有的前端技术栈都可以在同一个项目下使用,包括未来的前端技术栈。?容错性:单个模块出现错误,不影响全局。?扩展:每个服务都可以独立横向扩展,以满足业务的扩展性和不必要的资源消耗。3、什么时候需要前端微服务?项目技术栈太老,有相关技能的开发人员少,功能扩展困难,重构成本高,维护成本高。?项目太大,代码编译慢,开发体质差。需要更高维度的解耦解决方案。?单一的技术栈无法满足您的业务需求。?需要将其他现有项目整合到主项目中。4.微前端的几种实现方式?iframe:iframe是最简单直接的方法。iframe有自己的沙箱隔离,允许多个应用程序同时在一个用户界面上运行。?路由分布式微前端:即不同的服务通过路由分布到不同的独立前端应用,典型代表阿里云。?BuildwithWebComponents技术:使用WebComponents构建框架无关的组件,然后在相应的框架中引入这些组件,适用于较小的模块。?自制框架兼容应用:代表性框架有single-spa和阿里的qiankun。在页面的适当位置引入或创建DOM。当用户操作时,加载相应的应用程序(触发启动应用程序),可以卸载应用程序。5.单体应用和微前端架构的比较?单体应用?微前端三、如何实现微前端应用1.基本概念实现一套微前端架构,可以分为四个部分。参考:https://alili.tech/archive/11...?Loader:是微前端架构的核心,主要用来调度子应用,决定什么时候展示哪些子应用。可以理解为电源。?Wrapper:有了loader,可以将已有的应用打包,让loader使用,相当于一个电源适配器。?主应用:一般是包含所有子应用公共部分的工程——相当于电气基础。?子应用:主应用内容区显示的很多应用——相当于你要使用的电器。于是就有了这样一个概念:电源(loader)→电源适配器(wrapper)→?电器基础(主应用)→?电器(子应用)?。一般来说,流程是这样的:用户访问index.html后,浏览器运行加载器的js文件,加载器到配置文件,注册配置文件中配置的各个子应用后,首先加载主应用程序(菜单等),然后通过路由确定远程动态加载子应用程序。2.预备知识?SystemJsSystemJS提供了一个通用的模块导入路径,支持传统模块和ES6模块。SystemJS有两个版本,6.x版本用于浏览器,0.21版本用于浏览器和node环境,两者使用方式不同。参考:https://github.com/systemjs/s...主要作为微服务中的加载器。值得注意的是,我们暂时没有选择使用system.js,因为经过研究,目前需要加载的资源很少,有点杀鸡用牛刀的感觉。目前我们的方法是动态创建脚本来引用资源,当然正统的做法是使用system.js。?singleSpasingle-spa是一个在前端应用程序中将多个javascript应用程序汇集在一起??的框架。主要充当包装器。参考:https://single-spa.js.org/doc...4.具体实现步骤首先需要两个前端工程,一个主工程,一个子工程。主项目有基本的登录和导航模块,其余主要业务逻辑在子项目中。因为好未来主要的前端技术栈是Vue,所以我们以Vue为例。当然,React和Angular也适用。1.子项目?先来看vue.config.js中修改publicPath的选项。一般我们在做项目的时候可以写'/'。这个选项表示从哪个地址加载资源文件,一般是从网站根目录加载,现在需要写成子项目的存放地址,可以在阿里云oss或者cdn上.devServer需要为跨域添加一个新的header,主要是因为我们在本地开发的时候,从主项目的端口号加载到子项目的端口号的资源也会跨域。输出选项应指明资源包的名称和运行环境。这里我们选择窗口。注意,如果使用system.js,这里必须指定umd模式。stats-webpack-plugin插件最初是用来描述依赖之间的相互引用关系的。现在我们用它来生成一个manifest.json文件。这个manifest.json文件里有什么?让我们来看看。这里我们主要使用入口点。可以看到这是启动子项目需要加载的入口文件。也就是说,我们请求主工程中的manifest.json文件,就知道需要加载哪些js了。这里我们也给css添加了一个scopesingle-spa-vue,这样子项目的css只能在这个样式前缀下生效,保证子项目的样式不会影响到主项目。?然后是main.js的修改。这里我们使用一个小插件single-spa-vue。这个插件的主要功能是导出single-spa框架需要的bootstrap、mount、unmount这三个生命周期。对应的还有single-spa-react,single-spa-angular。可以看出,我们的写法可以保证子项目作为一个模块运行在主项目中,也可以单独打包部署,甚至可以两者并行存在。?router.js要修改路由器,我们需要添加一个baseUrl。我们的项目叫'learnSystem',前后都要加'/'。这个url前缀就是我们在主项目中的模块路由前缀。没有匹配的子项。2.主项目?添加single-spa-config.js文件。主要步骤是动态创建脚本标签,远程加载子项目需要的js文件,然后注册微服务模块'learnSystem'。一开始这个文件是在main.js中加载的,后来发现如果子工程加载速度可以比主工程快,那么就会有问题,然后我们把它放在App创建的钩子函数中。vue,importwithrequire保证主工程加载后子工程加载。上图中,LEARN_URL可以根据环境配置不同的值。比如开发环境可以配置localhost+子项目的端口号,生产环境可以配置在线链接。?router.jsrouter需要添加模糊匹配*,否则如果直接刷新子模块当前页面,会先进入主工程的404页面?App.vue一开始我们的App.vue只有一个router-view,现在我们需要提供一个容器用于子项目渲染,还记得single-spa-vue的范围吗?确保子项的样式只在这个div内生效3.主项目与子项通信通常,我们建议尽量避免这种情况-将这些应用程序耦合在一起。如果您发现自己经常在应用程序之间执行此操作,您可能需要考虑这些单独的应用程序实际上应该只是一个应用程序。但是,有些场景需要通信。比如子项目请求接口发现token过期,需要通知主项目退出并跳转到登录界面。我们使用了一个简单的方法。由于这两个项目属于同一个窗口,所以它们也共享一个窗口对象。在主工程中注册一个方法,挂载到window对象上。在子项目中调用该方法。实现他们的目标。4.优化打包配置由于主工程和子工程都使用了相同的部分依赖,可以考虑不将公共依赖打包到主工程中,提高打包效率,修改vue.config.js请注意可以共享的资源,需要保证主项目和子项目使用的依赖版本号一致,或者兼容同一个版本。如果两个项目之间的依赖版本差异太大,那么这不是可以共享的资源。五、结论这套方案只能说是一套可行的方案。其实还有很多可以优化的地方,大家可以一起讨论。例如:?上面我们解决了子应用和主应用的css交互,但是不要忘了js,如何像iframe一样创建一个沙箱,让应用之间互不影响,包括全局变量事件等处理是比较重要的一点。?我们无法避免使用vuex与vue,那么不同的应用程序可以共享vuex数据吗?因为有些数据比如权限可能是通用的。或者更进一步,应用本身是否可以控制某个状态是应用的私有变量还是其他应用可以访问的公共变量。?我们当前子项目的资源是懒加载的,即只有当路由匹配到'learnSystem'时才加载子项目的资源。其实预加载可能更好一些,就是在应用空闲的时候加载子应用的资源。?子应用的嵌套,微前端如何嵌套微前端。?主应用程序如何向子应用程序发送状态。虽然不完美,但不妨碍我们体验微前端带来的好处。以上内容我们将与大家分享,也请大家关注未来魔法学校近年的成长情况。
