We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
而提到微前端就离不开微服务,大家对微服务都比较熟悉了,微服务允许后端体系结构通过松散耦合的代码库进行扩展,每个代码库负责自己的业务逻辑,并公开一个API,每个API均可独立部署,并且各自由不同的团队拥有和维护。
前端架构经历了从单体,到前后端分离,再到微服务,最终发展到现在的微前端的过程如下图所示:
微前端的思路是把微服务的架构引入到前端,其核心都是要能够以业务为单元构建端到端的垂直架构,使得单个的团队能够独立自主的进行相关的开发,同时又具备相当的灵活性,按需求来组成交付应用。
“微前端”一词最早于2016年底在 ThoughtWorks 技术雷达中提出的。它将微服务的概念扩展到了前端世界。微前端的核心思路其实是远程应用程序,包含组件/模块/包的运行时加载。
如上图,对于用户而言,访问的是一个微前端的容器(container),容器加载运行在远程服务上的应用,把这些远程应用作为组件/模块/包在本地浏览器中加载。
上面说了很多,总结一下就是:微前端(Micro-Frontends)是一种类似于微服务的架构,他将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。各个前端应用还可以独立开发、独立部署、独立运行。微前端不是单纯的前端框架或者工具,而是一套架构体系。
在前面我们看到的微前端之前的架构,所有的前端还是一个单体,前端团队会依赖所有的服务或者后台的 API,前端开发会成为整个系统的瓶颈。使用微前端,就是要让前端业务从水平分层变为垂直应用的一部分,进入业务团队,剥离耦合。
那么微前端有什么好处,为什么要采用微前端架构呢?
因此,微前端和微服务的本质都是关于去耦合。而只有当应用程序达到一定规模时,这才开始变得更有意义。
微前端不是一个库,是一种前端架构的设计思路,要实现微前端,本质上就是在运行时远程加载应用。如下列了一些实现方案,但不仅仅只是这样:
即通过路由将不同的业务分发到不同的、独立前端应用上。其通常可以通过 HTTP 服务器的反向代理来实现。这种方案,不涉及前端的改造,完全是依靠运维层面的配置。
当在浏览器里访问 www.nrp.com/app1 的时候,其实访问的是 app1 这个应用;当访问 www.nrp.com/app2 的时候,其实访问的是 app2 这个应用。要实现这个功能,就可以用 nginx 的反向代理来实现路由分发:
http { server { listen 80; server_name www.nrp.com; location / { root /www/wwwroot/www.nrp.com/; index index.html index.htm; } location /app1 { proxy_pass http://www.app1.com/; } location /app2 { proxy_pass http://www.app2.com/; } } }
通过 http 服务分发不同的路由到不同的独立应用上,虽然实现上很简单,但是缺点也相当明显:
HTML 内联框架元素 <iframe> 表示嵌套的正在浏览的上下文,能有效地将另一个 HTML 页面嵌入到当前页面中。
<iframe>
<iframe src="http://www.baidu.com/"></iframe>
iframe 可以创建一个全新的独立的宿主环境,这意味着我们的前端应用之间可以相互独立运行。通过给 iframe 的 src 指定不同的地址,来实现加载不同的子应用。
<template v-for="app in appList"> <iframe v-show="currAppCode == app.code" :key="app.code" :src="app.src" ></iframe> </template>
使用 iframe 来加载不同的微应用,接入非常简单,且由于 iframe 天然的沙箱环境使得 js 和样式隔离都非常完美。但他存在以下一些问题:
这个方案和第一种方案很像,都是需要通过 nginx 来将路由分发到不同的应用上,可以认为是它的升级版,区别是这种方式的系统在运行时将由主应用来进行路由管理,子应用的加载、启动、卸载以及通信都需要依靠主应用来完成。
这种方式的代表开源框架就是 qiankun。
作为微前端的基座应用,是整个应用的入口,负责承载当前微应用的展示和对其他路由微应用的转发,对于当前微应用的展示,一般是由以下几步构成:
对于路由分发而言,以采用vue-router开发的基座SPA应用来举例,主要是下面这个流程:
当浏览器的路径变化后,vue-router 会监听 hashchange 或者 popstate 事件,从而获取到路由切换的时机。 最先接收到这个变化的是基座的 router,通过查询注册信息可以获取到转发到那个微应用,经过一些逻辑处理后,采用修改 hash 方法或者 pushState 方法来路由信息推送给微应用的路由,微应用可以是手动监听 hashchange 或者 popstate 事件接收,或者采用 React-router,vue-router 接管路由,后面的逻辑就由微应用自己控制。
Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的 Web 应用中使用它们。
它主要有三项技术组件:
<template>
<slot>
这里有一个在线的 Web Components 示例
随后,在各自的 HTML 文件里,创建相应的组件元素,编写相应的组件逻辑。一个典型的 Web Components 应用架构如下图所示:
可以看到这边方式与我们上面使用 iframe 的方式很相似,组件拥有自己独立的 Scripts 和 Styles,以及对应的用于单独部署组件的域名。然而它并没有想象中的那么美好,要直接使用纯 Web Components 来构建前端应用的难度有:
MicroApp 借鉴了Web Component 的思想,通过 CustomElement 结合自定义的 ShadowDom,将微前端封装成一个类 Web Component 组件,从而实现微前端的组件化渲染。
Module Federation 是 webpack 5 中的一个新特性,能轻易实现在两个使用 webpack 构建的项目之间共享代码,通俗点讲,Module Federation 提供了能在当前应用加载其他应用的能力。这就为实现微前端提供了另一种可能。
EMP 就是基于这个特性研发出来的微前端解决方案。
对于 Module Federation,它有几个概念:
所以,当前模块想要加载其他模块,就要有一个引入动作,同样,如果想让其他模块使用,就需要有一个导出动作。通过以下 2 个 webpack 插件配置参数可以实现模块的导入和导出。
这与基座模式完全不同,像 iframe 和 qiankun 都是需要一个基座(中心容器)去加载其他子应用。而 Module Federation 任意一个模块都可以引用其他应用,同时也可以导出被其他应用使用,这就没有了容器中心的概念。
想要使用 Module Federation 功能需要引入 webpack 5 中内置的插件 ModuleFederationPlugin,通过配置该插件来完成。比如 base 应用需要引入 expose 应用里导出的 HelloWorld 模块,可以这样配置:
expose 的 vue.config.js:
new webpack.container.ModuleFederationPlugin({ name: "app_expose", filename: "remoteEntry.js" exposes: { "./HelloWorld.vue": "./src/components/HelloWorld.vue", }, shared: { vue: { singleton: true, }, }, }),
base 应用的 vue.config.js:
new webpack.container.ModuleFederationPlugin({ name: "app_base", filename: "remoteEntry.js", remotes: { app_expose: "app_expose@http://localhost:8082/remoteEntry.js", }, shared: { vue: { singleton: true, }, }, }),
使用 expose 应用的 HelloWorld 模块:
<template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png" /> <HelloWorld msg="Welcome to Your Vue.js" /> </div> </template> <script lang="js"> import { defineComponent } from "vue"; import HelloWorld from "app_expose/HelloWorld.vue"; export default defineComponent({ name: 'HomeView', components: { HelloWorld }, }) </script>
webpack 5 与之前版本的模块管理对比图:
讲了这么多的优点和实现,那么微前端是不是解决前端开发问题的银弹呢?当然不是。所有的架构都是取舍和权衡,这个世界上并不存在银弹,微前端架构和微服务一样也存在他的弊端,单体架构未必就差。
微前端架构还在不断发展之中,本文提到的 nginx / iframe/ qiankun/Web Components / Module Federation 只是诸多解决方案中的一小部分,前端的发展变化和生态系统实在是丰富,相信未来会有更多以及更好用的微前端架构的出现。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
什么是微前端
而提到微前端就离不开微服务,大家对微服务都比较熟悉了,微服务允许后端体系结构通过松散耦合的代码库进行扩展,每个代码库负责自己的业务逻辑,并公开一个API,每个API均可独立部署,并且各自由不同的团队拥有和维护。
前端架构经历了从单体,到前后端分离,再到微服务,最终发展到现在的微前端的过程如下图所示:
微前端的思路是把微服务的架构引入到前端,其核心都是要能够以业务为单元构建端到端的垂直架构,使得单个的团队能够独立自主的进行相关的开发,同时又具备相当的灵活性,按需求来组成交付应用。
“微前端”一词最早于2016年底在 ThoughtWorks 技术雷达中提出的。它将微服务的概念扩展到了前端世界。微前端的核心思路其实是远程应用程序,包含组件/模块/包的运行时加载。
如上图,对于用户而言,访问的是一个微前端的容器(container),容器加载运行在远程服务上的应用,把这些远程应用作为组件/模块/包在本地浏览器中加载。
上面说了很多,总结一下就是:微前端(Micro-Frontends)是一种类似于微服务的架构,他将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。各个前端应用还可以独立开发、独立部署、独立运行。微前端不是单纯的前端框架或者工具,而是一套架构体系。
为什么需要微前端
在前面我们看到的微前端之前的架构,所有的前端还是一个单体,前端团队会依赖所有的服务或者后台的 API,前端开发会成为整个系统的瓶颈。使用微前端,就是要让前端业务从水平分层变为垂直应用的一部分,进入业务团队,剥离耦合。
那么微前端有什么好处,为什么要采用微前端架构呢?
因此,微前端和微服务的本质都是关于去耦合。而只有当应用程序达到一定规模时,这才开始变得更有意义。
如何实现微前端架构
微前端不是一个库,是一种前端架构的设计思路,要实现微前端,本质上就是在运行时远程加载应用。如下列了一些实现方案,但不仅仅只是这样:
纯 nginx 路由转发
即通过路由将不同的业务分发到不同的、独立前端应用上。其通常可以通过 HTTP 服务器的反向代理来实现。这种方案,不涉及前端的改造,完全是依靠运维层面的配置。
当在浏览器里访问 www.nrp.com/app1 的时候,其实访问的是 app1 这个应用;当访问 www.nrp.com/app2 的时候,其实访问的是 app2 这个应用。要实现这个功能,就可以用 nginx 的反向代理来实现路由分发:
通过 http 服务分发不同的路由到不同的独立应用上,虽然实现上很简单,但是缺点也相当明显:
使用 iframe 创建容器
HTML 内联框架元素
<iframe>
表示嵌套的正在浏览的上下文,能有效地将另一个 HTML 页面嵌入到当前页面中。iframe 可以创建一个全新的独立的宿主环境,这意味着我们的前端应用之间可以相互独立运行。通过给 iframe 的 src 指定不同的地址,来实现加载不同的子应用。
使用 iframe 来加载不同的微应用,接入非常简单,且由于 iframe 天然的沙箱环境使得 js 和样式隔离都非常完美。但他存在以下一些问题:
组合式应用路由分发
这个方案和第一种方案很像,都是需要通过 nginx 来将路由分发到不同的应用上,可以认为是它的升级版,区别是这种方式的系统在运行时将由主应用来进行路由管理,子应用的加载、启动、卸载以及通信都需要依靠主应用来完成。
这种方式的代表开源框架就是 qiankun。
作为微前端的基座应用,是整个应用的入口,负责承载当前微应用的展示和对其他路由微应用的转发,对于当前微应用的展示,一般是由以下几步构成:
对于路由分发而言,以采用vue-router开发的基座SPA应用来举例,主要是下面这个流程:
当浏览器的路径变化后,vue-router 会监听 hashchange 或者 popstate 事件,从而获取到路由切换的时机。
最先接收到这个变化的是基座的 router,通过查询注册信息可以获取到转发到那个微应用,经过一些逻辑处理后,采用修改 hash 方法或者 pushState 方法来路由信息推送给微应用的路由,微应用可以是手动监听 hashchange 或者 popstate 事件接收,或者采用 React-router,vue-router 接管路由,后面的逻辑就由微应用自己控制。
使用 Web Components 技术构建
Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的 Web 应用中使用它们。
它主要有三项技术组件:
<template>
和<slot>
元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。这里有一个在线的 Web Components 示例
随后,在各自的 HTML 文件里,创建相应的组件元素,编写相应的组件逻辑。一个典型的 Web Components 应用架构如下图所示:
可以看到这边方式与我们上面使用 iframe 的方式很相似,组件拥有自己独立的 Scripts 和 Styles,以及对应的用于单独部署组件的域名。然而它并没有想象中的那么美好,要直接使用纯 Web Components 来构建前端应用的难度有:
MicroApp 借鉴了Web Component 的思想,通过 CustomElement 结合自定义的 ShadowDom,将微前端封装成一个类 Web Component 组件,从而实现微前端的组件化渲染。
Module Federation
Module Federation 是 webpack 5 中的一个新特性,能轻易实现在两个使用 webpack 构建的项目之间共享代码,通俗点讲,Module Federation 提供了能在当前应用加载其他应用的能力。这就为实现微前端提供了另一种可能。
EMP 就是基于这个特性研发出来的微前端解决方案。
对于 Module Federation,它有几个概念:
所以,当前模块想要加载其他模块,就要有一个引入动作,同样,如果想让其他模块使用,就需要有一个导出动作。通过以下 2 个 webpack 插件配置参数可以实现模块的导入和导出。
这与基座模式完全不同,像 iframe 和 qiankun 都是需要一个基座(中心容器)去加载其他子应用。而 Module Federation 任意一个模块都可以引用其他应用,同时也可以导出被其他应用使用,这就没有了容器中心的概念。
想要使用 Module Federation 功能需要引入 webpack 5 中内置的插件 ModuleFederationPlugin,通过配置该插件来完成。比如 base 应用需要引入 expose 应用里导出的 HelloWorld 模块,可以这样配置:
expose 的 vue.config.js:
base 应用的 vue.config.js:
使用 expose 应用的 HelloWorld 模块:
webpack 5 与之前版本的模块管理对比图:
微前端的问题和缺点
讲了这么多的优点和实现,那么微前端是不是解决前端开发问题的银弹呢?当然不是。所有的架构都是取舍和权衡,这个世界上并不存在银弹,微前端架构和微服务一样也存在他的弊端,单体架构未必就差。
微前端架构还在不断发展之中,本文提到的 nginx / iframe/ qiankun/Web Components / Module Federation 只是诸多解决方案中的一小部分,前端的发展变化和生态系统实在是丰富,相信未来会有更多以及更好用的微前端架构的出现。
The text was updated successfully, but these errors were encountered: