***single-spade 2018年 Single-SPA诞生了, single-spa 是一个用于前端微服务化的 JavaScript 前端解决 方案 (本身没有处理样式隔离, js 执行隔离) 实现了路由劫持和应用加载(即根据不同的路由加载不同的应用): ***
子应用
- 安装 single-spa-vue。 注: 这里是以vue为基础作为子应用开发,若使用react,则是安装single-spa-react
npm i single-spa-vue
- main.js 文件的修改
注: bootstrap ,mount ,unmount , 这三个方法,子应用必须抛出,不然主应用是无法访问子应用的
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import singleSpaVue from 'single-spa-vue' // 引入single-spa
Vue.config.productionTip = false
const appOptions = {
el: '#vue', // 挂载到父应用中id为vue的标签中
router,
render: h => h(App)
}
if (!window.singleSpaNavigate) {
delete appOptions.el
new Vue(appOptions).$mount('#app')
} else {
__webpack_public_path__ = 'http://localhost:10000/' // 解决子应用内的路由切换,主应用获取的子应用静态文件的根路径问题
}
// 使用 singleSpaVue 包装 Vue,
// 包装后返回的对象中vue包装好的三个生命周期,bootstrap,mount,unmount,
const vueLifeCycle = singleSpaVue({ Vue, appOptions })
// 协议接入,我们定好了协议,父应用会调用这些方法
export const bootstrap = vueLifeCycle.bootstrap;
export const mount = vueLifeCycle.mount;
export const unmount = vueLifeCycle.unmount;
- 路由设置
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: "/vueApp", // 这里设置成主应用的访问子应用路径的名称
routes
})
export default router
- 因为父应用需要加载子应用,所以我们配置好main.js之后,我们需要将子应用打包成一个lib去给父应用使用,所以我们在子应用的vue配置文件vue.config.js中使用以下代码:
module.exports = {
configureWebpack:{
output:{
library:'singleVue',
library:'umd'
},
devServer:{
port :10000
}
}
}
主应用
- 安装single-spa
npm i single-spa
- mian.js 文件的编辑
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import { registerApplication, start } from 'single-spa'; // 引入single-spa 的api,registerApplication是注册应用的api, start是启动single-spa 主应用的api
Vue.config.productionTip = false
// 加载子应用的js
async function loadScript (url) {
return new Promise((resolve, reject) => {
// 创建标签,并将标签加到head中
let script = document.createElement('script');
script.src = url;
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
})
}
// 注册应用
registerApplication('vueApp',
async () => {
// 加载子组件导出的类库和资源,注意先后顺序
await loadScript(`http://localhost:10000/js/chunk-vendors.js`);
await loadScript(`http://localhost:10000/js/app.js`)
return window.singleVue; // 返回子应用里导出的生命周期,mount,ummount,bootstrap
// 注: window.singleVue是在子应用的配置文件声明的一个library的名称,通过umd挂载到window上
},
location => location.pathname.startsWith('/vueApp'));// 当用户切换到/vueApp的路径下时,加载刚才定义子子应用
start();
new Vue({
router,
render: h => h(App)
}).$mount('#app')
- App.vue 文件
<template>
<div id="app">
<router-link to="/vueApp">加载Vue应用</router-link> |
<!-- 将子应用将会挂载到 id="vue" 标签中 -->
<div id="vue"></div> <!--这个标签是子应用要挂载的标签-->
</div>
</template>
-
父子应用间通信
在子应用的main.js文件修改
export const bootstrap = lifeCycle.bootstrap ;
export const mount = = (props) => {
console.log(props) // props 里有父应用传过来的参数及方法
Vue.prototype.$fun = props.fun // fun是父应用传过来的方法,可以将它挂载到Vue实例上,可以进行全局调用
return lifeCycle.mount (props);
};
export const unmount = lifeCycle.unmount;
在子应用中调用fun方法
this.$fun({name: 'Swayer'}) // fun的参数是传给父应用的,实现了子传值给父应用,参数可以是任何数据类型
父应用的main.js
registerApplication('vueApp',
async () => {
console.log('加载模块')
await loadScript('http://localhost:10000/js/chunk-vendors.js')
await loadScript('http://localhost:10000/js/app.js')
return window.singleVue
},
location => location.pathname.startsWith('/vue'),
{
age: 1,
fun: (p) => {
console.log(p, '父应用') // 这里是接收子应用调用这个方法所传的参数值
}
} // 这里是父应用传给子应用的参数
)