微前端从零到剖析qiankun源码 -- single-spa玩法!

479 阅读2分钟

single-spa 到底是干嘛的

single-spa 仅仅是一个子应用生命周期的调度者。 single-spa 为应用定义了 boostrap, load, mount, unmount 四个生命周期回调

只要写过 SPA 的人都能理解,无非就是生、老、病、死。不过有几个点需要注意一下:

  • Register 不是生命周期,指的是调用 registerApplication 函数这一步
  • Load 是开始加载子应用,怎么加载由开发者自己实现(等会会说到)
  • Unload 钩子只能通过调用 unloadApplication 函数才会被调用

OK,上面 4 个生命周期的回调顺序是 single-spa 可以控制的,我能理解,那什么时候应该开始这一套生命周期呢?应该是有一个契机来开始整套流程的,或者某几个流程的。

契机就是当 window.location.href 匹配到 url 时,开始走对应子 App 的这一套生命周期嘛。所以,single-spa 还要监听 url 的变化,然后执行子 app 的生命周期流程。

到此,我们就有了 single-spa 的大致框架了,无非就两件事:

  • 实现一套生命周期,在 load 时加载子 app,由开发者自己玩,别的生命周期里要干嘛的,还是由开发者造的子应用自己玩
  • 监听 url 的变化,url 变化时,会使得某个子 app 变成 active 状态,然后走整套生命周期

image.png

SingleSpa 实战

构建子应用

  1. 安装包
vue create spa-vue
npm install single-spa-vue
  1. 修改main.js
import singleSpaVue from 'single-spa-vue';
const appOptions = {
   el: '#vue',
   router,
   render: h => h(App)
}
// 在非子应用中正常挂载应用
if(!window.singleSpaNavigate){
 delete appOptions.el;
 new Vue(appOptions).$mount('#app');
}
const vueLifeCycle = singleSpaVue({
   Vue,
   appOptions
});
// 子应用必须导出 以下生命周期 bootstrap、mount、unmount
export const bootstrap = vueLifeCycle.bootstrap;
export const mount = vueLifeCycle.mount;
export const unmount = vueLifeCycle.unmount;
export default vueLifeCycle;

3.配置子路由基础路径

const router = new VueRouter({
  mode: 'history',
  base: '/vue',
  routes
})

页面路由匹配到/vue就会去加载这个子应用

4.将子模块打包成类库,方便加载

module.exports = {
    configureWebpack: {
        output: {
            library: 'singleVue',
            libraryTarget: 'umd'
        },
        devServer:{
            port:10000
        }
    }
}

构建主应用

1.构建路由和价值root

<div id="nav">
    <router-link to="/vue">vue项目</router-link> 
    <div id="vue"></div>
</div>

2.主应用注册子应用

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
// 自己构建的
const loadScript = async (url)=> {
  await new Promise((resolve,reject)=>{
    const script = document.createElement('script');
    script.src = url;
    script.onload = resolve;
    script.onerror = reject;
    document.head.appendChild(script)
  });
}
import { registerApplication, start } from 'single-spa';
registerApplication(
    'singleVue',
    async ()=>{
        await loadScript('http://localhost:10000/js/chunk-vendors.js');
        await loadScript('http://localhost:10000/js/app.js');
        return window.singleVue
    },
    // 当匹配到/vue开头的,开始价值子应用
    location => location.pathname.startsWith('/vue')
)
start();
new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

3.解决资源问题,动态设置子应用publicPath

if(window.singleSpaNavigate){
  __webpack_public_path__ = 'http://localhost:10000/'
}

效果展示

image.png

写在最后:下一篇将着重使用大量时间给大家详细《微前端从零到剖析qiankun源码 --- singleSpa源码分析》