最终实现的效果:
- vue cli
使用npm管理包自行安装基础环境啊
npm install -g @vue/cli 安装vue脚手架
- 创建主应用app1和子项目app2
vue create app1
vue create app2
- 改造主项目app1
npm i single-spa-vue -S
main.js改造
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import { registerApplication, start } from 'single-spa'
Vue.config.productionTip = false
// 远程加载子应用
function createScript(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)
})
}
// 记载函数,返回一个 promise
function loadApp(url, globalVar) {
// 支持远程加载子应用
return async () => {
await createScript(url + '/js/chunk-vendors.js')
await createScript(url + '/js/app.js')
// 这里的return很重要,需要从这个全局对象中拿到子应用暴露出来的生命周期函数
return window[globalVar]
}
}
// 子应用列表
const apps = [
{
name: 'app2',
app: loadApp('http://localhost:8082', 'app2'),
activeWhen: location => location.pathname.startsWith('/app2'),
customProps: {}
},
]
// 注册子应用
for (let i = apps.length - 1; i >= 0; i--) {
registerApplication(apps[i])
}
new Vue({
router,
mounted() {
// 启动
start()
},
render: h => h(App)
}).$mount('#app')
vue.config.js
const package = require('./package.json')
module.exports = {
// 告诉子应用在这个地址加载静态资源,否则会去基座应用的域名下加载
publicPath: '//localhost:8081',
// 开发服务器
devServer: {
port: 8081
},
configureWebpack: {
// 导出umd格式的包,在全局对象上挂载属性package.name,基座应用需要通过这个全局对象获取一些信息,比如子应用导出的生命周期函数
output: {
// library的值在所有子应用中需要唯一
library: package.name,
libraryTarget: 'umd'
}
}
}
App.vue
<template>
<div id="app">
<div id="nav"><!-- 主应用 -->
<router-link to="/home">app1</router-link> |
<router-link to="/about">app1-about</router-link> |
<router-link to="app2#x/home">app2</router-link> |
<router-link to="app2#/about">app2-about</router-link>
<button @click="test">测试</button>
</div>
<router-view/>
<!-- 子应用容器 -->
<div id = "microApp">
</div>
</div>
</template>
<script>
export default {
methods: {
test(){
this.$router.push({path: "/app2/home"});
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
}
#nav a {
font-weight: bold;
color: #2c3e50;
}
#nav a.router-link-exact-active {
color: #42b983;
}
</style>
src目录下新建views目录并新建about.vue和home.vue
about.vue
<!-- /views/About.vue -->
<template>
<div class="about">
<h1>app1 about page</h1>
</div>
</template>
home.vue
<!-- /views/Home.vue -->
<template>
<div class="home">
<h1>app1 home page test</h1>
</div>
</template>
src下新建router目录并新建index.js
index.js:
import VueRouter from 'vue-router'
import Vue from 'vue'
import Home from '@/views/home'
import About from '@/views/about'
Vue.use(VueRouter)
const routes = [
{ path: '/home', component: Home },
{ path: '/about', component: About },
// { path: '*', component: Hello },
];
const router = new VueRouter({
mode: 'history',
// 通过环境变量来配置路由的 base url
// base: process.env.VUE_APP_BASE_URL,
routes
});
export default router
package.json:
"scripts": {
"serve": "vue-cli-service serve",
"serve:micro": "vue-cli-service serve --mode micro",
"build": "vue-cli-service build --mode buildMicro"
},
app1项目改造完毕。
- 子应用app2应用改造
main.js:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import singleSpaVue from 'single-spa-vue'
Vue.config.productionTip = false
/**
* 子应用main.js
*/
const appOptions = {
el: '#microApp',
router,
render: h => h(App)
}
// if(window.singleSpaNavigate) {
// __webpack_public_path__="http://localhost:8082/"
// }
// 支持应用独立运行、部署,不依赖于基座应用
if (!window.singleSpaNavigate) {
delete appOptions.el
new Vue(appOptions).$mount('#app')
}
// 基于基座应用,导出生命周期函数
const vueLifecycle = singleSpaVue({
Vue,
appOptions
})
export function bootstrap () {
console.log('app2 bootstrap')
return vueLifecycle.bootstrap(() => {})
}
export function mount () {
console.log('app2 mount')
return vueLifecycle.mount(() => {})
}
export function unmount () {
console.log('app2 unmount')
return vueLifecycle.unmount(() => {})
}
vue.config.js
const package = require('./package.json')
module.exports = {
// 告诉子应用在这个地址加载静态资源,否则会去基座应用的域名下加载
publicPath: '//localhost:8082',
// 开发服务器
devServer: {
port: 8082
},
configureWebpack: {
// 导出umd格式的包,在全局对象上挂载属性package.name,基座应用需要通过这个全局对象获取一些信息,比如子应用导出的生命周期函数
output: {
// library的值在所有子应用中需要唯一
library: package.name,
libraryTarget: 'umd'
}
}
}
App.vue:
<template><!-- 子应用 -->
<div id="vue">
<!-- <div>"Welcome to Your Vue.js App"</div> -->
<router-view />
</div>
</template>
- src下新建views目录并新建about.vue和home.vue
about.vue
<!-- /views/About.vue -->
<template>
<div class="about">
<h1>app2 about page</h1>
</div>
</template>
home.vue
<!-- /views/Home.vue -->
<template>
<div class="home">
<h1>app2 home page</h1>
</div>
</template>
src目录下新建router目录并新建index.js
index.js
import VueRouter from 'vue-router'
import Vue from 'vue'
import Home from '@/views/home'
import About from '@/views/about';
import Hello from '@/components/HelloWorld';
Vue.use(VueRouter)
/**
* 子应用路由
*/
const routes = [
{ path: '/home', component: Home },
{ path: '/about', component: About },
{ path: '*', component: Hello }
// {
// path: '/about',
// component: () => import(/* webpackChunkName: "about" */'../views/about.vue'),
// meta: {
// keepAlive: true
// }
// },
];
const router = new VueRouter({
// mode: 'history',
// 通过环境变量来配置路由的 base url
// base: process.env.VUE_APP_BASE_URL,
routes
});
export default router
package.json下改造script属性值
"scripts": {
"serve": "vue-cli-service serve",
"serve:micro": "vue-cli-service serve --mode micro",
"build": "vue-cli-service build --mode buildMicro"
},
app2改成完成!
开始运行
1、在app1目录执行cmd命令:
npm run serve
执行结果:
DONE Compiled successfully in 12673ms 下午5:05:14
App running at:
- Local: http://localhost:8081/
- Network: http://192.168.43.189:8081/
Note that the development build is not optimized.
To create a production build, run yarn build.
2、在app2目录执行cmd命令:
npm run serve
执行结果:
DONE Compiled successfully in 9440ms 下午5:05:53
App running at:
- Local: http://localhost:8082/
- Network: http://192.168.43.189:8082/
Note that the development build is not optimized.
To create a production build, run yarn build.
打开浏览器输入
http://localhost:8081/
结束
运行完成后,你刷新非主页面路由会直接404,请看我的下一篇博客
页面刷新404问题
引入ElementUi继续改造demo:
vue+single-spa+ElementUi项目demo
出现了npm依赖没有安装的问题,根据提示自行安装