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
import {
start,
addGlobalUncaughtErrorHandler,
registerMicroApps,
} from "qiankun";
//注册微应用
const apps = [
{
name: "micro-app1",
entry: "/micro-app1/", //入口 两端必须有'/'
container: "sub-app-container", // 微应用挂载的DOM
activeRule: "/app1", //
props: {
menuName: "微应用APP1",
submenu: [{ menuUrl: "/app1/dashboard", menuName: "工作台" }],
},
},
];
registerMicroApps(apps, {
//只会执行一次
beforeLoad: (app) => {},
beforeMount: (app) => {},
afterMount: (app) => {},
beforUnmount: (app) => {},
afterUnmount: (app) => {},
});

由于是多台服务器部署,entryactiveRule必须不一样,否则刷新后会变成微应用的页面,entry会被注册为微应用的运行时__webpack_public_path__。例如主应用的当前地址是 http://wwwqiangian.com,按如上配置加载micro-app1 时则会拼接entry,用http://www.qianqian.com/micro-app1/请求微应用的index.html。子应用和 nginx 的配置也需配合改动。

主应用路由设置

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
export default new Router({
mode: "history",
routes: [
{ path: "/login", name: "login", component: () => import("@/views/login") },
{
path: "/",
component: Layout,
redirect: "/dashboard",
name: "BaseLayout",
children: [
// 主应用路由
{
path: "/dashboard",
name: "dashboard",
meta: { title: "工作台", affix: true },
component: () => import("@/views/dashboard/index.vue"),
},
],
},
// 确保所有微应用的第一次载入会载入到Layout
{
path: "*",
component: Layout,
},
],
});

在主应用动态添加子应用的路由

beforeLoad钩子函数中动态添加路由,方便后续路由的管理

1
2
3
4
5
6
7
8
9
10
11
beforeLoad: (app) => {
const { submenu } = app.props.data;
const { entry } = app;
for (const menu of submenu) {
router.addRouter("BaseLayout", {
path: menu.menuUrl,
name: menu.menuUrl,
meta: { title: menu.menuName, isMicroApp: true, entry },
});
}
};

nginx 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
location {
charset utf-8;
root /var/www/html;
try files $uri $uri/ /index.html;
}
# 代理后端,需要将微应用的全部后端都配置到这里,假设后端地址是http://192.168.1.29:38028
location /backend {
proxy_pass http://192.168.1.29:38028;
}
# 反向代理微应用 假设微应用的服务器nginx Ip 是 192.168.1.30
location ^~ /micro-app1/ {
proxy_pass http:// 192.168.1.30/micro-app1/;
proxy_set_header Host $host:$server_port;
}

Vue 子应用

修改 main.js 配合 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
import "./public-path";
import Vue from "vue";
import VueRouter from "vue-router";
import App from "./App.vue";
import routes from "./router";
import store from "./store";
let instance = null;
function render(props = {}) {
const { container } = props;
router = new VueRouter({
base: window.__POWERED_BY_QIANKUN__ ? "/app1/" : "/micro-app1/",
// /micro-app1 与 entry保持一致确保能通过主应用nginx独立访问。
mode: "history",
routes,
});

instance = new Vue({
router,
store,
render: (h) => h(App),
}).$mount(container ? container.querySelector("#app") : "#app");
}

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

export async function bootstrap() {
console.log("[vue] vue app bootstraped");
}
export async function mount(props) {
console.log("[vue] props from main framework", props);
// props 包含注册时写入的参数
render(props);
}
export async function unmount() {
instance.$destroy();
instance.$el.innerHTML = "";
instance = null;
router = null;
}
1
2
3
4
// public-path.js
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

为了微应用的 css,js 等文件能正常访问,publicPath需要与entry一致。

1
2
3
4
//vue.config.js
module.exports = {
publicPath: process.env.NODE_ENV === "development" ? "/" : "/micro-app1/",
};

同时打包后的文件需要部署在二级目录micro-app1(与entry一致)下。

nginx 配置

1
2
3
4
5
6
7
8
9
location {
# add_header Access-Control-Allow-Origin *;
# add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
# add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

charset utf-8:
root var/www/html:
files $uri $uri/ /micro-app1/index.html
}

访问

http://www.qianqian.com/app1/dashboard是在利用乾坤框架内嵌微应用
http://www.qianqian.com/micro-app1/dashboard可以独立访问微应用micro-app1