# 微前端概述
# 什么是微前端
微前端 概念的出现,是在我了解到后端 server less 相关概念时候出现的,其实大致的思路是差不多的,每一个功能(服务)独立部署、独立运行,每一个模块都拆分成更小,更易于管理的 微应用
微前端的历史由来 我们的开发模式在不同的 web 时代的实现方式也是在逐渐变化的:
web1.0:那时候信息比较简单,就是单纯嵌套网页(css + html + js(jquery)+ cms 后台),数据简单,展示简单
web2.0:这时候出现了前后端分离(css + html + js + ajax),前后端做出分离以后,前端对于开发模式上面,就做出了很多的研究和琢磨,这期间最火的,就是 MVC(Module View Controller)
web3.0:由于在这个阶段,我们要处理的就不只是上面那些需求了,要考虑用户体验(渲染和响应速度)、开发速度等,技术根据需求而生,这时候,react、vue、angular 等框架就应用而生了
微前端架构具备以下几个核心价值:
技术栈无关 主框架不限制接入应用的技术栈,微应用具备完全自主权
独立开发、独立部署 微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新
增量升级
在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略
- 独立运行时 每个微应用之间状态隔离,运行时状态不共享
微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。
# 如何使用并落地微前端
- 微前端方案一(iframe) 在最早我们用来实现 微前端 的方式,是通过 iframe 来做的,页面里面嵌套一个 iframe,通过设置 url 来做微应用的划分,这样可以保证了每一个微应用 都是独立部署,独立运行的,哪一个就算出现了问题,也不会影响到其它的应用,可以保证在一定范围内用户正常使用
iframe 对于一些简单的静态、纯展示类的页面是很好的方案,但是如果有需要做交互、信息共享、数据更新等行为的时候,iframe 就不能完全满足我们的需求了,iframe 不能满足的需求有以下几点:
在 iframe 内的页面做切换的时候,浏览器回退的时候,就会出现页面跳转错误 由于它的特性可以完美的隔离上下文之间的所有资源,但是隔离的同时在对于一些需要做共享资源,iframe 的特性就没有办法突破了 当每一次 iframe 的启动,都是需要重新做资源的加载 如果在嵌套 iframe 的页面是有那种类似二次确认的弹窗,由于是覆盖整个页面的,iframe 页面可以 resize ,但是 resize 也会影响到嵌套页面的展示效果,毕竟从局部变成了整个页面了嘛 对于 iframe 的状态捕捉,假设 iframe 子应用加载、预渲染、渲染后、卸载、卸载后、加载报错的情况;整个生命周期处理上面都需要做很多的处理,麻烦而复杂,对 iframe 生命周期的方案做的不好的话,意外的情况就会影响到用户的使用,就得不偿失了
- 微前端方案二(single-spa) 一个在国外流行很久的方案 single-spa 完美的处理了所有上述 iframe 所存在的问题,接下来我们所有的案例也是基于 single-spa 去做的效果展示,下面是 single-spa 官方对于 single-spa 诞生所做的阐述:
single-spa 的诞生,是通过从现在的一些框架:react、angular、vue 的生命周期中获得了灵感,将生命周期 运用于整个应用,避免应用程序被束缚。
现在 single-spa 几乎支持任何框架。 由于 JavaScript 因其许多框架的寿命短而臭名昭著,我们决定让它在 任何您想要的框架都易于使用。
基于 Webpack5 联邦模块 这个方案是直接将一个应用的包应用于另一个应用,同时具备整体应用一起打包的公共依赖抽取能力。 让应用具备模块化输出能力,其实开辟了一种新的应用形态,即 “中心应用”,这个中心应用用于在线动态分发 Runtime 子模块,并不直接提供给用户使用 对微前端而言,这张图就是一个完美的主应用,因为所有子应用都可以利用 Runtime 方式复用主应用的 Npm 包和模块,更好的集成到主应用中。
对微前端而言,这张图就是一个完美的主应用,因为所有子应用都可以利用 Runtime 方式复用主应用的 Npm 包和模块,更好的集成到主应用中。 模块联邦的使用方式如下:
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
// other webpack configs...
plugins: [
new ModuleFederationPlugin({
name: "app_one_remote",
remotes: {
app_two: "app_two_remote",
app_three: "app_three_remote",
},
exposes: {
AppContainer: "./src/App",
},
shared: ["react", "react-dom", "react-router-dom"],
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
chunks: ["main"],
}),
],
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
模块联邦本身是一个普通的 Webpack 插件 ModuleFederationPlugin,插件有几个重要参数:
name 当前应用名称,需要全局唯一。 remotes 可以将其他项目的 name 映射到当前项目中。 exposes 表示导出的模块,只有在此申明的模块才可以作为远程依赖被使用。 shared 是非常重要的参数,制定了这个参数,可以让远程加载的模块对应依赖改为使用本地项目的 React 或 ReactDOM。 比如设置了 remotes: { app_tw0: "app_two_remote" },在代码中就可以直接利用以下方式直接从对方应用调用模块:
import { Search } from "app_two/Search";
这个 app_two/Search 来自于 app_two 的配置:
// app_two 的 webpack 配置
export default {
plugins: [
new ModuleFederationPlugin({
name: "app_two",
library: { type: "var", name: "app_two" },
filename: "remoteEntry.js",
exposes: {
Search: "./src/Search",
},
shared: ["react", "react-dom"],
}),
],
};
2
3
4
5
6
7
8
9
10
11
12
13
14
正是因为 Search 在 exposes 被导出,我们因此可以使用 [name]/[exposes_name] 这个模块,这个模块对于被引用应用来说是一个本地模块。
模块联邦为更大型的前端应用提供了开箱解决方案,并已经作为 Webpack5 官方模块内置,可以说是继 Externals 后最终的运行时代码复用解决方案。
另外 Webpack5 还内置了大量编译时缓存功能,可以看到,无论是性能还是多项目组织,Webpack5 都在尝试给出自己的最佳思路,期待 Webpack5 正式发布,前端工程化会迈向一个新的阶段。
# 主流微前端框架横向对比
- SingleSpa
- Qiankun(阿里-蚂蚁)
- MicroApp(京东)
初探 MicroApp,一个极致简洁的微前端框架 (opens new window)
- Garfish(字节)
字节跳动Garfish微前端实现原理 (opens new window)
- icestark(阿里-飞冰)
微前端 之 icestark 源码阅读 (opens new window)
# 参考
← 小程序开发框架 微前端之SingleSpa →