一、什么是微前端?
微前端一词第一次出现是在工作思维(ThoughtWorks)2016年的技术雷达( Technology Radar )中。微前端是一种架构,是将整个巨石应用拆分成多个可独立开发、部署、上线,运行的小型应用(子应用),对外暴露一个控制台应用(父应用)来统一管理各个子应用的运行状态,多个子应用间在用户无感情况下往复切换。
现代应用痛点:
- 项目中的组件和功能模块会越来越多,导致整个项目的打包速度变慢;
- 因为文件夹的数量会随着功能模块的增多而增多,查找代码会变得越来越慢;
- 如果只改动其中一个模块的情况,需要把整个项目重新打包上线;
- 目录层级和模块层级过深而且文件又多,定位文件会越来越慢;
- 所有的项目都只能使用同一技术框架如:react、vue等;
微前端的优势
- 无技术栈限制:主框架不限制接入应用的技术栈,子应用具备完全自主权
- 独立开发,独立部署,子应用的仓库独立,前后端可独立进行开发,部署完成后主框架自动完成同步更新
- 独立运行:每个项目都可以作为一个完整的单独项目去运行。独立运行时,每个子应用之间状态隔离,运行时状态不共享
二、微前端架构解决方案
- 2018 single-spa 是一个用于前端微服务化的 javascript 前端解决方案,(本身没有处理样式隔离,js 执行隔离)实现了路由的劫持和应用加载;
- 2019 qiankun 基于 single-spa 提供了更加开箱即用的 api(single-spa+sandbox+import-html-entry)做到了,技术栈无关,并且接入简单。
三、single-spa
解决的问题
single-spa 实现了路由劫持和应用加载的功能: 监听路由加载子模块
Single-spa 是一个将多个单页面应用聚合为一个整体应用的 JavaScript 微前端框架。
基座提供注册逻辑、子应用提供三个协议接入方法和打包格式
子应用可以独立部署,运行时动态加载主子应用完全解耦,技术栈无关,靠的是协议接入(子应用必须导出 bootstrap,mount,unmount 方法)
基座
在基座里我们调用single-spa提供给我们的registerApplication和start的方法
singleSpa.registerApplication:这是注册子项目的方法。参数如下:
appName: 子项目名称
applicationOrLoadingFn: 子项目注册函数,用户需要返回 single-spa 的生命周期对象。后面我们会介绍single-spa的生命周期机制
activityFn: 回调函数入参 location 对象,可以写自定义匹配路由加载规则。
singleSpa.start:这是启动函数。
注意:父项目的 vue-router 要开启history模式。
子项目
如果想注册为一个子项目,还需要 single-spa-vue 的包装。
在main.js中引入 single-spa-vue,传入Vue对象和vue.js挂载参数,就可以实现注册。它会返回一个对象,里面有single-spa 需要的生命周期函数。使用export导出即可。
子项目最重要的就是提供三个方法 bootstrap、mount、unmount 和 打包格式
import singleSpaVue from "single-spa-vue";
import Vue from 'vue'
const vueOptions = {
el: "#microApp",
router,
store,
render: h => h(App)
};
// singleSpaVue包装一个vue微前端服务对象
const vueLifecycles = singleSpaVue({
Vue,
appOptions: vueOptions
});
// 导出生命周期对象
export const bootstrap = vueLifecycles.bootstrap; // 启动时
export const mount = vueLifecycles.mount; // 挂载时
export const unmount = vueLifecycles.unmount; // 卸载时
webpack的处理
只是导出了,还需要挂载到window。
在项目目录下新建 vue.config.js, 修改我们的webpack配置。我们修改webpack output内的 library 和 libraryTarget 字段。
output.library: 导出的对象名
output.libraryTarget: 导出后要挂载到哪里
同时,因为我们是远程调用,还需要设置 publicPath 字段为你的真实服务地址。否则加载子chunk时,会去当前浏览器域名的根路径寻找,有404问题。
因为我们本地的服务启动是localhost:3000,所以我们就设置 //localhost:3000。
独立运行
我们的子服务现在是无法独立运行的,现在我们改造为可以独立 + 集成双模式运行
single-spa 有个属性,叫做 window.singleSpaNavigate。如果为true,代表就是single-spa模式。如果false,就可以独立渲染。
改造一下子项目的main.js :
/**** 添加这里 ****/
if (!window.singleSpaNavigate) { // 如果不是single-spa模式
delete vueOptions.el;
new Vue(vueOptions).$mount('#app');
}
这样,我们就可以独立访问子服务的 index.html
使用 single-spa 进行前端架构设计可以带来很多好处:
例如:
在同一页面上使用多个前端框架而不用刷新页面] (react,vue等 )
独立部署每一个单页面应用
新功能使用新框架,旧的单页应用不用重写可以共存
改善初始加载时间,延迟加载代码
缺点:
- 在上面父项目加载子项目的代码中,我们可以看到。我们要注册一个子服务,需要一次性加载2个JS文件。如果需要加载的JS更多,甚至生产环境的 bundle 有唯一hash, 那我们还能写死文件名和列表吗?
- 侵入性太强,不仅要在入口导出生命周期,还要更改 Webpack 配置
JS Entry 的接入微应用方式来简陋了,我们更希望是通过一个 index.html 的 url 来接入微应用
啥都没有,比如 JS、CSS 隔离,主微应用通信等这些都需要别的小库来解决