Vue3.js + qiankun 搭建项目

参考:

  1. https://zhuanlan.zhihu.com/p/466194553
  2. https://blog.csdn.net/stormeye_/article/details/112311459
  3. https://www.cnblogs.com/goloving/p/14995114.html

1 配置主应用

新建一个文件夹qiankun-front

cd qiankun-front
vue create main
cd main
npm install vue-router -s
npm install qiankun -s

2 配置主应用的路由

2.0 修改挂载id

因为有多个项目,如果不修改,id会重复,所以修改index.html和main.js文件

修改index.html

修改main.js

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import startQiankun from "./micro";

createApp(App).use(router).mount("#qiankun-main");

startQiankun();

2.1 配置router

import { createRouter, createWebHistory } from "vue-router";
import Home from "../pages/Home.vue";

const routerHistory = createWebHistory();

const router = createRouter({
  history: routerHistory,
  routes: [
    {
      path: "/",
      redirect: "/home",
    },
    {
      path: "/home",
      component: Home,
    },
  ],
});

export default router;

3 注册微应用

3.0 新建 micro 文件夹

新建 micro/app.js 文件。
目前还没有子应用,所以数组为空。

const apps = [];

export default apps;

新建 micro/index.js 文件。

import {
  registerMicroApps,
  addGlobalUncaughtErrorHandler,
  start,
} from "qiankun";
import apps from "./apps.js";

registerMicroApps(apps, {  
  beforeLoad: (app) => console.log("before load", app.name),
  beforeMount: [(app) => console.log("before mount", app.name)],
});

addGlobalUncaughtErrorHandler((e) => {
  console.log("Global Error", e);
});

export default start;

4 搭建子项目

vue create vue-child
cd vue-child
npm install vue-router -s

4.0 修改挂载id

4.1 配置路由

import Home from "../pages/Home.vue";

const routes = [
  {
    path: "/vue",
    redirect: "/vue/home",
  },
  {
    path: "/vue/home",
    component: Home,
  },
];

export default routes;

4.2 修改 main.js

import { createApp } from "vue";
import App from "./App.vue";
import routes from "./router";
import { createRouter, createWebHistory } from "vue-router";

let instance = null;
let router = null;

/**
 * 渲染函数
 * 两种情况:主应用生命周期钩子中运行 / 微应用单独启动时运行
 */
function render() {
  const routerHistory = createWebHistory();

  router = createRouter({
    history: routerHistory,
    routes: routes,
  });

  createApp(App).use(router).mount("#vue-child");
}

// 独立运行时,直接挂载应用
if (!window.__POWERED_BY_QIANKUN__) {
  console.log("挂载应用");
  render();
}

/**
 * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
 * 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
 */
export async function bootstrap() {
  console.log("Vue Child bootstraped");
}

/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
export async function mount(props) {
  console.log("Vue Child mount", props);
  render(props);
}

/**
 * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
 */
export async function unmount() {
  console.log("Vue Child unmount");
  instance.$destroy();
  instance = null;
  router = null;
}

4.3 新建 public-path.js

if (window.__POWERED_BY_QIANKUN__) {
  // 动态设置 webpack publicPath,防止资源加载出错
  // eslint-disable-next-line no-undef
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

4.4 修改 vue.config.js

如果默认没有这个文件的话,就要在根目录下面新建

const path = require("path");

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

5 主应用注册微应用

修改micro/app.js

const apps = [
  {
    name: "vue-child",
    entry: "//localhost:8090",
    container: "#frame",
    activeRule: "/vue",
  },
];

export default apps;

6 父子应用传参

qiankun使用initGlobalState(state)定义全局状态,这个方法的返回值是一个实例
这个实例的方法有:

  1. onGlobalStateChange: 注册watcher函数,在当前应用监听全局状态
  2. setGlobalState:用来修改全局状态。
    设置新的值时,内部将执行浅检查,如果检查到globalState发生改变则触发通知,通知到所有的watcher函数
  3. offGlobalStateChange:移除当前应用的状态监听,取消watcher函数 - 该实例不再响应globalState变化。微应用 umount 时会默认调用

遇到的问题

1 端口被占用

https://www.runoob.com/w3cnote/windows-finds-port-usage.html

netstat -aon|findstr "想要查看的端口名称"


发现正在被占用
解决办法:

taskkill /T /F /PID 9652

2

原因:
vue3不用destory销毁实例,用unmount

import { createApp } from "vue";
import App from "./App.vue";
import routes from "./router";
import { createRouter, createWebHistory } from "vue-router";
let instance = null;
let router = null;

/**
 * 渲染函数
 * 两种情况:主应用生命周期钩子中运行 / 微应用单独启动时运行
 */
function render() {
  const routerHistory = createWebHistory();

  router = createRouter({
    history: routerHistory,
    routes: routes,
  });
  instance = createApp(App);
  instance.use(router).mount("#vue-iam");
}

// 独立运行时,直接挂载应用
if (!window.__POWERED_BY_QIANKUN__) {
  console.log("挂载应用");
  render();
}

/**
 * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
 * 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
 */
export async function bootstrap() {
  console.log("Vue Child bootstraped");
}

/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
export async function mount(props) {
  console.log("子组件 mount", props);
  render(props);
}

/**
 * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
 */
export async function unmount() {
  console.log("Vue Child unmount");
  instance.unmount();
  instance = null;
  router = null;
}
posted @ 2022-04-24 15:57  bcj7wi3kd5h1wd6  阅读(403)  评论(0编辑  收藏  举报