其实早就想写一篇关于微前端实践的文章了,几个月之前就看过有关微前端的视频,也查过一些文档,但是好像没有总结,现在又忘记一些了,今天实操了一遍,这里就总结一下,正好实习公司工作小组项目采用的就是微前端。今天先讲解一下single-spa,后面在讲解qiankun。
插曲:今天本来跟着别人一起敲代码,但是发现使用vue-cli脚手架创建项目老是报错,error403。昨天我在公司是可以使用的,通过npm是可以下载包的,但是今天打开电脑就发现报错。找了很多博客,解决一下几个问题:
一:(不记得截屏去了,尴尬)使用vue-cli 创建项目时报错,大致是说,npm 中的插件存在版本问题,后面通过修改./vuer中的配置为true,就可以使用脚手架创建项目。
二:今天在安装single-spa-vue这个包时,包error403,查了一些文章,都说是npm publish的问题,可是我这都没发布包了,怎么可能,后面详细解读错误,找到一个npm 镜像 是公司内部的源,这一下就知道是啥意思了,我Mac没有安装VPN连接公司的内网,所以造成了这一些问题,还有一个就是npm源的问题,可以切换到淘宝源
三:好久没有使用react 了,今天发现create-react-app 版本升级了,之前的不进行维护了,版本为4.0.3,小伙伴记得跟新。
single-spa是微前端解决方案的一种解决措施,single-spa由国外大佬发明。single-spa主要步骤是,在主应用中注册所有可能加载的微应用,微应用的声明必须在入口函数中暴露出三个钩子函数(bootstrap,mount,unmount),提供三个函数给主应用使用,bootstrap为启动准备,mount为挂载,unmount为销毁。主应用通过发送请求加载子应用打包好的lib库,然后执行子应用的lib就行。
1,首先创建一个主应用(可以是vue,react,其他)和子应用
vue create parent-vue //我这里采用了vue
vue create child-vue
2,安装single-spa
// 在主应用中加载single-spa
npm i single-spa --save
// 在子应用中加载single-spa-vue或者single-spa-react
npm i single-spa-vue --save
3,配置主应用的环境,并注册子应用
import Vue from 'vue'
import App from './App.vue'
import router from './router'
// 在主应用中引入single-sap
import { registerApplication,start } from "single-spa";
Vue.config.productionTip = false
// 声明一个函数,用来加载打包好的库
async function loadScript (url) {
return new Promise((resolve,reject)=>{
console.log('go')
let script = document.createElement('script');
script.src = url;
// 加载成功执行成功回调
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
})
}
// 进行注册
registerApplication('childVue',
async () => {
console.log('jiazai ')
// 在这里加载子应用打包出来的 app.js chunk-vendors.js 两个类库,注意加载循序
await loadScript(`http://localhost:10010/js/chunk-vendors.js`);
await loadScript(`http://localhost:10010/js/app.js`)
//加载子应用打包的lib之后,window上面挂载子应用对象,对象中包含钩子函数,将其返回出去
return window.singleVue
},
location => location.pathname.startsWith('/vue')
)
// 启动主应用
start();
new Vue({
router,
render: h => h(App)
}).$mount('#app')
注意:由于主应用与子应用之间存在跨域问题,所以主应用请求加载子应用的时候得进行跨域处理,上面代码使用jsonp,script标签自带跨域功能。
4,配置子应用
import Vue from 'vue'
import App from './App.vue'
import router from './router'
// 引入single-spa-vue微服务插件
import singleSpaVue from "single-spa-vue";
Vue.config.productionTip = false
// new Vue({
// router,
// render: h => h(App)
// }).$mount('#app')
// 生成配置对象
const appOptions = {
el: '#vue',
router,
render: h => h(App)
}
// 子引用必须向外暴露三个钩子函数
const singleLifeCycle = new singleSpaVue({
Vue,
appOptions // 将配置对象传过去
})
// 这里劫持主应用来请求子应用的路由,由于主应用的域名和子应用不同,所以这里劫持,修改域名
if(window.singleSpaNavigate){
__webpack_public_path__ = 'http://localhost:10010/'
}
// 如果主应用没有请求子应用,单独请求子应用,注意挂载点
if(!window.singleSpaNavigate){
delete appOptions.el;
new Vue(appOptions).$mount('#app')
}
// 实例对象上有所需暴露的三个钩子函数
export const bootStrap = singleLifeCycle.bootstrap;
export const mount = singleLifeCycle.mount;
export const unmount = singleLifeCycle.unmount;
注意:配置子应用的时候,按照single-spa协议必须得暴露三个钩子函数。
5,配置子应用打包成为lib
// 在配置中,将子应用打包成lib,给父引用调用
module.exports = {
configureWebpack:{
output:{
library:'singleVue',
libraryTarget:'umd'
},
devServer:{
port:10010
}
}
}
// umd 格式,会将打包好的lib文件挂载到,引用的Window属性上
// 所以父应用可以通过window.bootstrap,window.mount...
在根目录创建一个vue.config.js文件,配置打包。library是打包后的应用名,libraryTarget是打包后的格式。(这里是vue子应用配置)
6,子应用路由配置
// 由于是在主应用上跳转路由,所以这里得在主应用路由基础上 去跳转
const router = new VueRouter({
mode: 'history',
base: '/vue',
routes
})
子应用打包后的文件
app.js
chunk-vendors.js
注意:主应用请求的时候,必须得先请求基础配置包chunk-vendors.js然后才是请求app.js。
其实single-spa文件实现是不难的,从上面看也就几行代码,主要是理解思路,代码是其次,路由跳转路径尤其得注意。
single-spa的缺点:
1,从上面的运行结果可以看出,主应用加载子应用会出现样式冲突,样式污染。
2,js也会存在同样的污染问题(主:window.a 子:window.a 当子应用挂载到主应用时,会出现问题)
3,主应用必须得手动加载子应用打包好的lib库文件,如果子应用比较多,比较麻烦。