前端微服务化搭建-qiankun

前言

建议主应用使用history模式,微应用使用hash模式。

主应用

先使用VUE CLI创建项目

1
vue ui

注意要选择router组件

安装qiankun

1
npm i qiankun -S

按如下创建目录

image-20220218175544513

其中

  • 微应用出口文件 index.js
  • 路由文件 micro_app_router.js
  • 配置函数文件 micro_app_setting.js

micro_app_router.js

1
2
3
4
5
6
7
8
9
10
// 微应用路由
const micro_app_router = [
{
name: "child", //用于应用名 容器id 应用路由基地址
url: "//localhost:9001", //应用路径(ip与端口)
// hidden: false,//是否启用该应用,默认false
menuName: "子应用", //自定义属性 根据需要自己配置(用在了菜单导航的名称)
},
];
export default micro_app_router;

micro_app_setting.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 引入路由
import $microAppRouter from "./micro_app_router";
// 微应用配置
const micro_app_setting = {};
export default micro_app_setting;
/**
* @description: 配置子应用
* @param {*}
* @return {*}
*/
micro_app_setting.microApps = () => {
let apps = [];
$microAppRouter.map((item) => {
if (!item.hidden) {
apps.push({
name: item.name, //应用名(不可重复)
entry: item.url, //默认加载应用路径(ip与端口)
container: `#${item.name}`, //容器id
activeRule: `/${item.name}`, //激活该应用的路径(子应用路由基地址)
...item,
});
}
});
return apps;
};

index.js

1
2
3
4
5
6
7
8
// 引入 qiankun  应用注册函数   开启函数
import { registerMicroApps, start } from "qiankun";
// 引入 微应用配置文件
import $microAppSetting from "./micro_app_setting";
//注册子应用
registerMicroApps($microAppSetting.microApps());
//开启
start();

main.js上最上方添加

1
2
// 引入微应用文件
import "./assets/utils/micro/index.js";

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<template>
<!-- 主应用dom id 不能与子应用dom id 重复 -->
<div>
<!-- 主应用 -->
<a href="/">主应用</a>
<!-- 子应用 -->
<a
v-for="item in microAppDom_Router"
:key="item.name"
:href="`/${item.name}/`"
>{{ item.menuName }}</a
>
<!-- 主应用路由出口 -->
<router-view></router-view>

<!-- 微应用dom容器 -->
<div
v-for="item in microAppDom_Router"
:key="item.name"
class="microAppBox"
:id="item.name"
></div>
</div>
</template>
<script>
// 引入子应用路由
import $microAppRouter from "./assets/utils/micro/micro_app_router";
export default {
name: "Home",
data() {
return {
// 默认路由
activeIndex: "/",
// 微应用容器及路由list
microAppDom_Router: $microAppRouter,
};
},
created() {},
};
</script>

微应用

项目根目录中添加vue.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const packageName = require("./package.json").name;
module.exports = {
// 服务配置
devServer: {
port: 9001, //端口号
//允许跨域
headers: {
"Access-Control-Allow-Origin": "*",
},
},
// webpack 配置
configureWebpack: {
output: {
library: `${packageName}-[name]`,
libraryTarget: "umd",
jsonpFunction: `webpackJsonp_${packageName}`,
},
},
};

src目录下添加public-path.js

1
2
3
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

package.json中添加

1
2
3
4
5
6
7
{
"eslintConfig": {
"globals": {
"__webpack_public_path__": true
}
}
}

main.js按如下修改

为了避免根 id #app 与其他的 DOM 冲突,需要限制查找范围。

主要是判断是否是在qiankun中打开是否渲染,以及导出qiankun生命周期需要的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";

Vue.config.productionTip = false;

// vue实例变量
let instance = null;
// render 函数
function render(props) {
if (props) {
console.log(props);
}
// 创建vue实例
instance = new Vue({
router,
store,
render: (h) => h(App),
}).$mount("#app");
}
// 是否使用了qiankun
if (!window.__POWERED_BY_QIANKUN__) {
// 未使用qiankun 调用render 函数创建vue
render();
}

/**
* bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
* 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
*/
export async function bootstrap(props) {
console.log(props);
}
/**
* 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
*/
export async function mount(props) {
render(props);
}
/**
* 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
*/
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = '';
instance = null;
router = null;
}

/**
* 可选生命周期钩子,仅使用 loadMicroApp(手动加载微应用) 方式加载微应用时生效
*/
export async function update(props) {
console.log("update props", props);
}

路由文件中

1
2
3
4
5
const router = new VueRouter({
mode: "hash",
base: window.__POWERED_BY_QIANKUN__ ? "/child/" : "/",
routes,
});

注意

当微应用为hash模式时,base可以不用设置。