最终实现的效果:
- 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 Vuefrom'vue'import Appfrom'./App.vue'import routerfrom'./router'import{ registerApplication, start}from'single-spa'
Vue.config.productionTip=false// 远程加载子应用functioncreateScript(url){returnnewPromise((resolve, reject)=>{const script= document.createElement('script')
script.src= url
script.onload= resolve
script.onerror= rejectconst firstScript= document.getElementsByTagName('script')[0]
firstScript.parentNode.insertBefore(script, firstScript)})}// 记载函数,返回一个 promisefunctionloadApp(url, globalVar){// 支持远程加载子应用returnasync()=>{awaitcreateScript(url+'/js/chunk-vendors.js')awaitcreateScript(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])}newVue({
router,mounted(){// 启动start()},render:h=>h(App)}).$mount('#app')
vue.config.js
constpackage=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>exportdefault{
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><divclass="about"><h1>app1 about page</h1></div></template>
home.vue
<!--/views/Home.vue--><template><divclass="home"><h1>app1 home page test</h1></div></template>
src下新建router目录并新建index.js
index.js:
import VueRouterfrom'vue-router'import Vuefrom'vue'import Homefrom'@/views/home'import Aboutfrom'@/views/about'
Vue.use(VueRouter)const routes=[{ path:'/home', component: Home},{ path:'/about', component: About},// { path: '*', component: Hello },];const router=newVueRouter({
mode:'history',// 通过环境变量来配置路由的 base url// base: process.env.VUE_APP_BASE_URL,
routes});exportdefault 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 Vuefrom'vue'import Appfrom'./App.vue'import routerfrom'./router'import singleSpaVuefrom'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.elnewVue(appOptions).$mount('#app')}// 基于基座应用,导出生命周期函数const vueLifecycle=singleSpaVue({
Vue,
appOptions})exportfunctionbootstrap(){
console.log('app2 bootstrap')return vueLifecycle.bootstrap(()=>{})}exportfunctionmount(){
console.log('app2 mount')return vueLifecycle.mount(()=>{})}exportfunctionunmount(){
console.log('app2 unmount')return vueLifecycle.unmount(()=>{})}
vue.config.js
constpackage=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><divclass="about"><h1>app2 about page</h1></div></template>
home.vue
<!--/views/Home.vue--><template><divclass="home"><h1>app2 home page</h1></div></template>
src目录下新建router目录并新建index.js
index.js
import VueRouterfrom'vue-router'import Vuefrom'vue'import Homefrom'@/views/home'import Aboutfrom'@/views/about';import Hellofrom'@/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=newVueRouter({// mode: 'history',// 通过环境变量来配置路由的 base url// base: process.env.VUE_APP_BASE_URL,
routes});exportdefault 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 successfullyin 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, runyarn build.
2、在app2目录执行cmd命令:
npm run serve
执行结果:
DONE Compiled successfullyin 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, runyarn build.
打开浏览器输入
http://localhost:8081/
结束
运行完成后,你刷新非主页面路由会直接404,请看我的下一篇博客
页面刷新404问题
引入ElementUi继续改造demo:
vue+single-spa+ElementUi项目demo
出现了npm依赖没有安装的问题,根据提示自行安装