转载本文,转载请注明出处:微信公众号EAWorld前端开发无疑是程序员中比较辛苦的存在。作为前端开发,必须掌握Javascript、HTML、CSS这三个基础。Javascript作为互联网时代最重要的开发语言,由于其设计上的局限性,一直在进化。它经历了ES3、ES5、ES6(ECMAScript2015)……简单的CSS无法满足你复杂的需求。你需要Less/Sass/Sytlus来增强你??的CSS的功能。这些远不止一小部分,你还需要知道:需要有网络基础知识,HTTP/REST/GraphQL等常用API接口需要知道浏览器的兼容性,什么IE,Chrome,Safari、Firefox等。你需要知道应用程序是如何打包的,了解Webpack,以及gulp、Babel、Parcel、Browserify和Grunt是如何工作的。需要熟悉HTMLDOM操作,需要了解jquery、d3js等相关工具库的区别React、AngularJS、VueJS等框架及其优缺点,这三个框架互不兼容,各有千秋拥有庞大的生态。虽然NodeJS主要用于后端开发,但很多前端工具链都与此相关,例如Buildtoolsnpm,yarn...如果你的项目足够复杂,需要引入Monorepo,使用lerna等工具,nx等来管理多个项目的包和依赖。你需要掌握基本的前端测试工具和框架,比如:Jasmin、Jest、Selenium、Mocha等,最可怕的是,这些东西发展日新月异。当你忙于学习ES8、ES9、ES10的新特性时,我今天想和你分享的希望不是压倒性的。压死前端开发小骆驼的最后一根稻草——微前端。内容:1.什么是微前端2.为什么需要微前端,微前端有什么优势3.如何实现微前端架构4.运行时微前端的具体实现5.问题与不足一、微前端简介一、什么是微前端提到微前端,就离不开微服务。每个人都熟悉微服务。微服务允许通过松散耦合的代码库扩展后端架构。每个代码库都负责自己的业务逻辑并公开一个API,每个API都可以独立部署,并且每个都由不同的团队拥有和维护。前端架构从单体,到前后端分离,再到微服务,最后到现在的微前端流程如下图:微前端就是将微服务的架构引入到前端,其核心是要能够基于业务单元构建一个端到端的垂直架构,从而单个团队可以独立进行相关开发,同时具有相当大的灵活性,可以根据需要形成和交付应用。“微前端”一词最早出现在2016年底的ThoughtWorks技术雷达中。它将微服务的概念扩展到前端世界。当前的趋势是构建位于微服务架构之上的功能强大且功能强大的浏览器应用程序(也称为单页应用程序)。随着时间的推移,通常由单个团队开发的前端层会增长并变得更难维护。微前端背后的想法是将网站或Web应用程序视为独立团队拥有的功能组合。每个团队都有其关心和擅长的不同业务或任务领域。一个团队是跨职能的,并端到端地开发其功能,从数据库到用户界面。然而,这个想法并不新鲜。它与“单体系统”概念有很多共同之处。过去,类似的做法被称为“垂直系统的前端集成”。但微前端显然是一个更友好、更轻量级的术语。在微服务架构中,后台服务已经按照业务进行了分离,而前端仍然是单体搭建的,通过网关调用不同的后台服务。这个微服务的思路是相反的,这也导致你的后端团队按照业务划分,前端团队还是一个整体。微前端可以有效改善这一点。微前端的核心思想其实就是一个远程应用,包括组件/模块/包的运行时加载。如上图所示,对于用户来说,access是一个微前端容器(container),它加载运行在远程服务上的应用程序,并将这些远程应用程序作为组件/模块/包加载到本地浏览器中。组件是底层UI库的构建块模块是相应运行时的构建块包是依赖解析器的构建块微前端是建议的应用程序II的构建块。为什么需要微前端?它的优点是什么?在我们之前看到的微前端架构中,所有的前端还是一个整体,前端团队会依赖所有的服务或者后端API,前端开发会成为整个系统的瓶颈。使用微前端就是让前端业务从一个水平层转变为垂直应用的一部分,进入业务团队,解耦。那么微前端有什么好处,为什么要采用微前端架构呢?每个团队独立开发,互不影响,独立开发,独立部署,微应用仓库独立,前后端可独立开发,主框架部署后自动同步更新增量升级,当面对各种复杂的场景时,通常很难升级或重构现有系统的全技术栈,而微前端是实现渐进重构的一种很好的手段和策略。由于它是在运行时加载的,因此无需重建即可添加、删除或替换前端的各个部分。无论技术如何,每个团队都应该能够在不与其他团队协调的情况下选择和升级其技术堆栈。也就是说,A应用可以使用React,B应用可以使用Vue,大家可以通过同一个微前端加载。独立运行时,各个微应用的状态是隔离的,运行时状态是不共享的。隔离团队代码,即使所有团队都使用相同的框架,也不要共享运行时。构建自包含的独立应用程序。不要依赖共享状态或全局变量。建立团队命名空间以避免冲突并明确CSS、事件、本地存储和cookie的所有权。所以微前端和微服务的本质就是解耦。只有当应用程序达到一定规模时,它才开始变得更有意义。3、如何实现微前端架构微前端不是库,而是前端架构的一种设计思想。要实现微前端,本质上就是在运行时远程加载应用程序。有几种实现微前端的想法。从构建的角度来看,分为编译时构建微前端和运行时构建微前端两种:编译时微前端通常将第三方库中的组件作为包,在构建时构建time引入依赖。这种实现需要重新编译引入新的微前端,不够灵活。编译时微前端可以通过WebComponents、Monorepo等方式实现,其中Monorepo非常流行,常用的工具有nx、rush、lerna等。运行时微前端就是将微前端动态注入到容器中应用程序一次加载或通过延迟加载按需加载。引入新的微前端时,无需构建,可以在代码中动态定义加载。我眼中的微前端更多指的是这种在运行时加载的微前端,因为独立构建、部署和测试才是我们对“微”的定义。从前后端职责层次来看,可以从前端实现,也可以从后端实现。通过客户端框架实现微前端通常需要客户端工具支持(听起来很有道理),支持微前端客户端开发的实现工具有很多,包括:Piral、OpenComponents、qiankun、Luigi、Frint.js等等。其中,乾坤由蚂蚁金服开发。它也可以通过辅助库在客户端实现,它可以为共享依赖、路由事件或不同的微前端及其生命周期提供一些基础设施。下面的示例是通过导入映射或打包特定块等机制处理共享依赖项。相关工具有Webpack5ModuleFederation、Siteless、SingleSPA、Postal.js等。在服务端实现微前端不仅可以在客户端实现,类似于服务端渲染,也可以在服务端实现边。服务端微前端的配套工具有:Mosaic、PuzzleJs、Podium、Micromono等。好了说了这么多,相信你是发呆了。你是如何实现的?让我们抛开架构,看看如何实现它。四、运行时微前端iframe的具体实现iframe可以在html中嵌入另外一个html。以下是使用iframe实现微前端的示例:
您的浏览器不支持iframes。
您的浏览器不支持iframe。
/body>如果不考虑体验问题,iframe几乎是完美的微前端解决方案。iframe提供了浏览器原生的隔离方案,可以完美解决样式隔离、js隔离等问题。但它最大的问题是它的隔离性无法突破,导致应用之间无法共享上下文,从而带来开发体验和产品体验上的问题。这里的主要问题包括:url不同步。浏览器刷新iframeurl状态丢失,后退和前进按钮无法使用。UI不同步,DOM结构不共享。全局上下文是完全隔离的,并且不共享内存变量。慢的。子应用每次进入,都需要重建浏览器上下文,重新加载资源。所以虽然使用iframe可以达到远程加载的效果,但是因为这些限制,很少有应用会使用它。Nginx路由使用Ngix路由,我们可以将不同的请求路由到不同的微前端应用。比如Nginx的路由能力,可以在前端动态请求不同的后端应用,每个后端应用独立运行,前端可以将这些不同的后端应用一起加载和编排。以下代码是Nginx配置。customers/users/admins代表三个不同的应用,前端通过路由加载位于不同服务的后端应用。worker_processes4;events{worker_connections1024;}http{server{listen80;root/usr/share/nginx/html;include/etc/nginx/mime.types;location/app1{try_files$uriapp1/index.html;}location/app2{try_files$uriapp2/index.html;}location/app3{try_files$uriapp3/index.html;}}}无论采用何种微前端架构,Nginx方向代理或其他API网关解决方案都可以提供方便灵活的后端路由能力。但这样一来,就需要定义一个通用的、可扩展的路由规则。否则引入新的应用时,需要修改Nginx的路由配置,非常不方便。Webpack5ModuleFederationWebpack5的ModuleFederation是一项激动人心的创新,可以轻松支持微前端的构建。模块联合允许JavaScript应用程序从另一个应用程序动态加载代码,共享过程中的依赖关系。如果使用ModuleFederation的应用程序没有联邦代码所需的依赖项,Webpack将从该联邦构建源下载缺少的依赖项。在ModuleFederation的上下文中,启动代码是一种强制策略,用于将运行时代码附加到远程容器的启动序列。这非常有用,因为无法通过Hooks访问ModuleFederation及其运行时,并且无法扩展它或添加一行代码来执行动态设置远程容器的公共路径等操作。这在普通的webpack应用程序中是微不足道的,但在支持模块联合远程编排的不可访问的自定义运行时容器中很难做到。简单来说,ModuleFederation注入一段运行时代码,负责加载和编排远程应用代码,可以管理和加载远程应用依赖。下面是对应的例子:module.exports={mode:'development',devServer:{port:8080,},plugins:[newModuleFederationPlugin({name:'container',remotes:{microFrontEnd1:'microFrontEnd1@http://localhost:8081/remoteEntry.js',microFrontEnd2:'microFrontEnd2@http://localhost:8082/remoteEntry.js',},})]};上面的代码是微前端容器端的配置,容器负责加载其他远程应用的代码。在此示例中,它加载了两个远程应用程序。module.exports={mode:'development',devServer:{port:8081,},plugins:[newModuleFederationPlugin({name:'microFrontEnd1',filename:'remoteEntry.js',exposes:{'./MicroFrontEnd1Index':'./src/index',},}),]};各个微前端的Webpack配置如上。使用ModuleFederationPlugin,可以使用remote加载远程应用,Expose可以将自己的组件暴露为远程组件。在容器中,只需要调用如下代码即可加载远程组件。导入'microFrontEnd1/MicroFrontEnd1Index';导入'microFrontEnd2/MicroFrontEnd2Index';ModuleFederation的加载流程如上图所示:localhost加载index.htmlmain.js是ModuleFederation的核心编排代码,负责加载远程组件。remoteEntry.js是ModuleFederation暴露的远程组件的代码。src_是打包后的代码,其中bootstrap_js是容器端的代码,index_js是微前端的代码。ModuleFederation实现了一种类似于动态链接库的能力,可以在运行时加载远程代码。远程代码本质上是加载在窗口上的全局变量。ModuleFederation可以帮助解决依赖问题。Javascrip作为一门古老的语言,不提供依赖管理,留给各个高手发挥的余地。ModuleFederation的缺点是依赖于Webpack5,包直接挂载为全局变量。EMP微前端是基于ModuleFederation的微前端解决方案。单SPA单页面应用是当今Web应用的主流。不同于传统的多页面应用,整个SPA只有一个页面,其内容是通过Javascript的函数加载的。SPA是一种仅包含一个HTML页面的Web应用程序。提供动态更新,允许在不刷新页面的情况下与页面交互。对于单页面应用程序,可以显着降低服务器负载并提高加载速度以获得更好的用户体验,因为SPA仅在之前加载整个页面时才按需导入数据。除了开发复杂,对SEO不友好外,页面应用最大的技术缺陷就是URL不适合分享,因为SPA只有一个地址。single-spa是一个在前端应用程序中组合多个JavaScript微前端的框架。使用单spa构建前端有很多好处,例如:在同一页面上使用多个框架而无需刷新页面(React、AngularJS、Angular、Embe)独立部署微前端使用新框架编写代码而无需重写现有框架拥有应用程序用于减少初始加载时间的延迟加载代码single-spa应用程序由以下部分组成:single-spa根配置,用于呈现HTML页面和注册应用程序的JavaScript。每个应用程序注册以下三样东西:名称、加载应用程序代码的函数、确定应用程序何时处于活动/非活动状态的函数以及作为模块打包为单页应用程序的应用程序。每个应用程序都必须知道如何从DOM启动、安装和卸载自身。传统SPA和单SPA应用程序之间的主要区别在于它们必须能够与其他应用程序共存,因为每个应用程序都没有自己的HTML页面。例如,React或AngularSPA应用程序。激活时,它们可以监听url路由事件并将内容放在DOM上。当处于非活动状态时,它们不会监听url路由事件,并且会完全从DOM中移除。单SPA注册应用程序具有普通SPA的所有功能,只是它没有HTML页面。SPA由许多已注册的应用程序组成,每个应用程序都有自己的框架。注册的应用程序有自己的客户端路由和自己的框架/库。他们呈现自己的HTML并且在安装时可以完全自由地做任何他们想做的事。mount的概念是指注册的应用程序是否正在将内容放在DOM上。它的活动函数决定了注册的应用程序是否被挂载。每当未安装已注册的应用程序时,它应该保持完全休眠状态直到安装。SingleSPA示例代码如下:1、微前端代码:importReactfrom"react";importReactDOMfrom"react-dom";importsingleSpaReactfrom"single-spa-react";importRootfrom"./root.component";constlifecycles=singleSpaReact({React,ReactDOM,rootComponent:Root,errorBoundary(err,info,props){//Customizetherooterrorboundaryforyourmicrofrontendhere.returnull;},});exportconst{bootstrap,mount,unmount}=lifecycles;SingleSPA的微前端是纯JS组件,not包含HTML,需要通过容器加载。2、容器的RootConfig在容器端。需要通过ImportMap或者Webpack来定义远程组件和注册远程应用。{"imports":{"@naughty/root-config":"//localhost:9000/naughty-root-config.js","@naughty/app":"//localhost:8500/naughty-app.js","反应":"https://cdn.jsdelivr.net/npm/react@16.13.1/umd/react.production.min.js","反应-dom":"https://cdn.jsdelivr.net/npm/react-dom@16.13.1/umd/react-dom.production.min.js"}}容器端的HTML文件使用importmaps来定义远程依赖,其中root-config是负责布局的代码用于远程应用程序注册和加载。同时,需要定义所有的共享依赖。在这个例子中,react和react-domimport{registerApplication,start}from"single-spa";registerApplication({name:"@single-spa/welcome",app:()=>System.import("https://unpkg.com/single-spa-welcome/dist/single-spa-welcome.js"),activeWhen:["/welcome"],});registerApplication('@naughty/app',()=>System.import('@naughty/app'),location=>location.pathname.startsWith('/app'));开始({urlRerouteOnly:true,});在root-config中,我们使用不同的url注册和加载了两个远程应用程序。/welcome将加载欢迎应用程序,而/app将加载我们的应用程序。SingleSPA的核心是使用不同的URL路由来加载远程组件。它可以与Webpack(打包时构建依赖)或ImportMap(在运行时使用浏览器导入依赖)一起工作。注意不要在微前端中混合使用这两种依赖机制。SingleSPA还提供了一个布局引擎,可以帮助您快速构建微前端。与ModuleFederation相比,SingleSPA的代码和生命周期管理更加清晰,提供了清晰的接口。缺点是需要通过importmaps手动管理共享依赖。做一个好的微前端并不容易,因为受限于浏览器和JS的一些特性。除了今天分享的内容,我们还面临很多挑战:如何解决css/js冲突,让组件和应用完全隔离;如何解决不同应用之间的通信;如何处理路由;如何保证UI风格的统一等。五、微前端存在的问题和缺点说了这么多优点和实现,微前端是不是解决前端开发问题的灵丹妙药?当然不是。所有的架构都是权衡取舍。这个世界上没有银弹。与微服务一样,微前端架构也有其缺点。单体架构不一定不好。1.微前端的构建通常比较复杂。从工具、打包到部署,微前端都比较复杂。世界上没有免费的午餐。对于小项目来说,它的成本太高了。2.每个团队可以使用不同的框架。这听起来很美好,但在实践中,除了支持遗留应用外,意义不大。同时,也带来了体验问题。能够从不同的框架远程加载代码是一回事,充分利用它们又是另一回事。3、性能方面,如果优化不好,微前端的性能可能会出现问题。至少微前端框架多了一层加载。如果不同的微前端使用不同的框架,每个框架都需要额外加载。微前端架构仍在开发中。本文提到的iframe/nginx/modulefederation/single-spa只是众多解决方案中的一小部分。前端和生态系统的发展变化真的很丰富。umd/乾坤、Piral、opencomonent等其他解决方案。使用的时候也可以选择标准的WebComponents或者ESModules来搭建微前端,但是这些标准的浏览器支持不是特别好,这是前端开发永远的痛。(诅咒IE)