父项目
1,npm install single-spa
2,index.html
<meta base="/parentPageName/"> //(1) 否则获取资源有问题
3, public/static/config.js
配置父项目前端项目打包名称:
const Glod = {
packageName: 'parentPageName', //(1) 前端包放置到服务器上的包名, 需要与index.html保持一致
};
配置子项目前端地址:
//single-spa 项目前端包地址
const SINGLE_DEV = {
childPageUrl: 'http://localhost:3000/', //(2)子项目前缀
}
4, vue.config.js
publicPath: '/parentPageName', //(1)
5, 在src下 创建single-spa-config.js
// singleSpa.registerApplication:这是注册子项目的方法。参数如下:
// appName: 子项目名称
// applicationOrLoadingFn: 子项目注册函数,用户需要返回 single-spa 的生命周期对象。后面我们会介绍single-spa的生命周期机制
// activityFn: 回调函数入参 location 对象,可以写自定义匹配路由加载规则。
// singleSpa.start:这是启动函数。
import * as singleSpa from 'single-spa'; //导入single-spa
/**
* runScript:一个promise同步方法。可以代替创建一个script标签,然后加载服务
*/
const runScript = async(url) => {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = url;
script.onload = resolve;
script.onerror = reject;
const firstScript = document.getElementsByTagName('script')[0];
firstScript.parentNode.insertBefore(script, firstScript);
})
};
// 子模块 注册微前端服务
singleSpa.registerApplication(
'uniChild',
async() => {
await runScript(apiAll.childPageUrl+'/config.js');
await runScript(apiAll.childPageUrl+'/js/chunk-vendors.js');
await runScript(apiAll.childPageUrl+'/js/app.js');
return window.uniChild; //(3),需要与子系统设置保持一致
},
location => (location.pathname.startsWith('/uniChildRoute') || location.pathname.startsWith(`/${Glod.packageName}/uniChildRoute`)) //(4) 配置微前端模块前缀
);
singleSpa.start(); // 启动
6, 配置子项目嵌入的位置
views下增加portal.vue
<div id="uniChildId"></div> //(5) 子项目注入的id
路由增加
{
path: '/uniChildRoute', // (4)
component: () => import('@/views/portal'),
}
子项目
1, npm install single-spa-vue
2, public/static/config.js
const Glod = {
basePageUrl: 'http://localhost:3000/', //(2), 前端项目地址
};
3,vue.config.js
module.exports = {
publicPath: nodeEnv !== 'development'? config.basePageUrl : '//localhost:3000',
configureWebpack: {
output: {
library: "uniChild", // 导出名称 (3)保持一致
libraryTarget: "window", //挂载目标
}
},
css: {
// 是否使用css分离插件 ExtractTextPlugin, 否则获取不到子项目样式
extract: false,
},
filenameHashing: false,// 关闭最终打包生成的文件后面带有hash码,因为父项目步骤5,需要固定入口js
}
4, main.js
import Vue from 'vue';
import singleSpaVue from 'single-spa-vue';
const vueOptions = {
el: '#uniChildId', //(5)需要与父组件
router,
store,
render: h => h(App)
}
// 判断是否为single-spa模式,如果不是,就独立渲染
if (!window.singleSpaNavigate) { // 如果不是single-spa模式
delete vueOptions.el;
new Vue(vueOptions).$mount('#app')
}
// singleSpaVue包装一个vue微前端服务对象
const vueLifecycles = singleSpaVue({
Vue,
appOptions: vueOptions
})
// 导出生命周期对象
export const bootstrap = vueLifecycles.bootstrap // 启动时
export const mount = vueLifecycles.mount // 挂载时
export const unmount = vueLifecycles.unmount // 卸载时
export default vueLifecycles
(1,2,3,4,5)注释需要保持一致