Vue3.0 + qiankun 微前端应用实践推荐

3,482 阅读2分钟

安装版本

"vue": "^3.0.0",
"@vue/cli-service": "~4.5.15",
"vue-router": "^4.0.0-0",
"qiankun": "^2.6.3",//只有主应用需要引入

准备

  • 两个项目

    主应用(基座):vue create my-test-qiankun

    微应用:vue create my-test-vue3

更改主应用my-test-qiankun

  1. src文件夹下新增modules文件夹,在modules文件夹下添加apps.jsindex.js
  2. apps.js里统一存微应用信息,其中属性信息要与之后微应用的内容相挂钩
// apps.js统一存放微应用信息
const apps = [
    {
        name: 'my-test-vue3',
        entry: '//localhost:9999',
        container: '#frame',
        activeRule: '/my-test-vue3'
    }
]

export default apps;
  1. index.js里注册微应用并抛出启动函数
import { registerMicroApps, addGlobalUncaughtErrorHandler, start } from 'qiankun'

// 微应用的信息
import apps from './apps';

/**
 * 注册微应用
 * @param {*} apps 微应用的注册信息
 * @param {*} Object 全局生命周期钩子 
 */

registerMicroApps(apps, {
    // qiankun 生命周期钩子 - 微应用加载前
  beforeLoad: (app) => {
    // 加载微应用前,加载进度条
    console.log('before load', app.name);
    return Promise.resolve();
  },
  // qiankun 生命周期钩子 - 微应用挂载后
  afterMount: (app) => {
    // 加载微应用前,进度条加载完成
    console.log('after mount', app.name);
    return Promise.resolve();
  },
})

/**
 * 添加全局的未捕获异常处理器
 */
addGlobalUncaughtErrorHandler(event => {
    console.error(event)
})

// 导出 qiankun 启动函数
export default start;
  1. App.vue里添加router-view,id="frame"将会是微应用的根节点
<template>
  <div id="main__application--title">这是主项目基座(主应用)</div>
  <router-view />
  <router-view>
    <div id="frame"></div>
  </router-view>
</template>
  1. main.js 引入start并执行
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import start from "./modules";

start();

createApp(App).use(store).use(router).mount("#app");

更改微应用my-test-vue3

  1. src文件夹下添加public-path.js
if(window.__POWERED_BY_QIANKUN__) {
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
  1. main.js(element-plus相关可不用)
import { createApp } from "vue";
import ElementPlus from "element-plus"
import "element-plus/theme-chalk/index.css"
import App from './App.vue'
import router from './router'
import store from './store'
import './public-path';

const app = createApp(App);
function render(props = {}) {
  const { container } = props;

  app.use(store)
  .use(router)
  .use(ElementPlus)
  .mount(container ? container.querySelector('#app') : '#app')
}

// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
  render();
}


/**
 * bootstrap : 在微应用初始化的时候调用一次,之后的生命周期里不再调用
 */
export async function bootstrap() {
  console.log('bootstrap');
}

/**
 * mount : 在应用每次进入时调用 
 */
export async function mount(props) {
  console.log('mount', props);
  render(props);
}

/**
 * unmount :应用每次 切出/卸载 均会调用
 */
export async function unmount() {
  console.log('unmount');
  app.unmount();
}
  1. router/index.js(路由组件可自由设置)
import { createRouter, createWebHistory } from "vue-router";
import NucleicTask from "../views/nucleic-task/nucleic-task.vue";
const { name } = require('../../package.json')

const routes = [
  {
    path: "/",
    name: "NucleicTask",
    component: NucleicTask,
  },
  {
    path: "/about",
    name: "About",
    component: () =>
      import("../views/About.vue"),
  },
];

const router = createRouter({
  history: createWebHistory(
    window.__POWERED_BY_QIANKUN__ ? `/${name}/` : "/"
  ),
  routes,
});

export default router;

  1. vue.config.js
const APP_NAME = require('./package.json').name;
const path = require("path");

module.exports = {
  devServer: {
    // 监听端口
    port: 9999,
    // 关闭主机检查,使微应用可以被 fetch
    disableHostCheck: true,
    // 配置跨域请求头,解决开发环境的跨域问题
    headers: {
      "Access-Control-Allow-Origin": "*",
    },
  },
  configureWebpack: {
    resolve: {
      alias: {
        "@": path.resolve(__dirname, "src"),
      },
    },
    output: {
      // 微应用的包名,这里与主应用中注册的微应用名称一致
      library: APP_NAME,
      // 将你的 library 暴露为所有的模块定义下都可运行的方式
      libraryTarget: "umd",
      // 按需加载相关,设置为 webpackJsonp_微应用名称 即可
      jsonpFunction: `webpackJsonp_${APP_NAME}`,
    },
  },
};

完成运行

微信截图_20220323171813.png

微信截图_20220323171953.png

微信截图_20220323172100.png

可能遇到的问题

  • 启动微应用时报__ webpack_public_path__ 未定义 解决:在 子应用 package.json 文件中 eslintConfig 配置全局变量后 重起服务
"eslintConfig": {
    ...,
    "globals": {
      "__webpack_public_path__": true
    }
  },