Vue3.js + qiankun 搭建项目
参考:
- https://zhuanlan.zhihu.com/p/466194553
- https://blog.csdn.net/stormeye_/article/details/112311459
- 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)定义全局状态,这个方法的返回值是一个实例
这个实例的方法有:
- onGlobalStateChange: 注册watcher函数,在当前应用监听全局状态
- setGlobalState:用来修改全局状态。
设置新的值时,内部将执行浅检查,如果检查到globalState发生改变则触发通知,通知到所有的watcher函数 - 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;
}