single-spa配置

279 阅读1分钟

父项目

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)注释需要保持一致