# qiankun 微前端
# 核心价值
微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。
# 组成部分
# 主应用
主要功能:
- 功能上:注册微应用
- 表现上:作为微应用的 layout,菜单,header 等
# 微应用
修改已有项目为微应用
- react
index.tsx
中导入public-path.js
文件
// public-path.js
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
// main.js
import "./public-path";
- 改造 render 函数,暴露三个生命周期
function render(props) {
const { container } = props;
ReactDOM.render(
<App />,
container
? container.querySelector("#reactApp")
: document.querySelector("#reactApp")
);
}
if (!window.__POWERED_BY_QIANKUN__) {
render({});
}
export async function bootstrap() {
console.log("[react16] react app bootstraped");
}
export async function mount(props) {
console.log("[react16] props from main framework", props);
render(props);
}
export async function unmount(props) {
const { container } = props;
ReactDOM.unmountComponentAtNode(
container
? container.querySelector("#reactApp")
: document.querySelector("#reactApp")
);
}
- 修改打包方式,和允许跨域
// config-overrides.js
const devServerConfig = () => config => {
return {
...config,
headers: {
'Access-Control-Allow-Origin': '*',
},
...
}
}
const publicPathPlugin = (config, env) => {
config.output = {
library: 'subReactApp',
libraryTarget: 'umd',
jsonpFunction: 'webpackJsonp_subReactApp',
globalObject: 'window',
}
return config
}
module.exports = {
webpack: override(
...
publicPathPlugin,
...
),
devServer: overrideDevServer(devServerConfig()),
}
- 修改路由 mode,与 baseUrl
//
import { Route, Switch, HashRouter } from "react-router-dom";
<HashRouter basename={!window.__POWERED_BY_QIANKUN__ ? "/reactone" : "/"}>
<Switch>
{routes.map((route) => {
return <RouteWithSubRoutes key={route.path} {...route} />;
})}
<Route component={NoDataPage} />
</Switch>
</HashRouter>;
- 去掉 404 页面
因为在当前微应用跳转其他微应用时,如果当前微应用有 404 页面,当前微应用以为它自己跳转到了不存在的页面就会出现异常
- 把微应用 layout 部分加上逻辑判断
在微应用中就不显示菜单这些了,当然这里指的是主应用提供菜单的做法
{window.__POWERED_BY_QIANKUN__ ? (去掉layout过后的内容):(原本的layout)
- vue
main.js
中导入public-path.js
文件
// public-path.js
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
// main.js
import "./public-path";
- 改造 render 函数,暴露三个生命周期
let instance = null;
const render = (props = {}) => {
const { container } = props;
instance = new Vue({
router,
store,
i18n,
render: (h) => h(App),
}).$mount(container ? container.querySelector("#vue") : "#vue"); // 这里是挂载到子应用的html中基座会拿到这个挂载后的html将其插入进去
};
if (!window.__POWERED_BY_QIANKUN__) {
// 子应用支持独立开发运行
render();
}
// 子应用相关协议,需要导出这三个方法
/* eslint-disable */
export async function bootstrap() {
console.log("[vue] vue app bootstraped");
}
/* eslint-disable */
export async function mount(props) {
console.log("[vue] props from main framework", props);
render(props); // 装载
}
/* eslint-disable */
export async function unmount() {
instance.$destroy(); // 卸载
instance = null;
}
- 修改打包方式,和允许跨域
// vue.config.js
module.exports = {
configureWebpack: (config) => {
config.output = {
...config.output,
library: "vueApp",
libraryTarget: "umd",
};
},
devServer: {
headers: {
"Access-Control-Allow-Origin": "*",
},
},
};
- 修改路由 mode,与 baseUrl
export default new Router({
mode: "history",
base: window.__POWERED_BY_QIANKUN__ ? "/vueApp" : process.env.BASE_URL,
...
});
这里的 /vueApp
就是在主应用在注册中使用的 url,主应用遇到 /vueApp
的路由便会去加载当前这个微应用
- 给 404 页面加上逻辑判断
因为在当前微应用跳转其他微应用时,如果当前微应用有 404 页面,当前微应用以为它自己跳转到了不存在的页面就会出现异常
{
...其他的路由
...(window.__POWERED_BY_QIANKUN__
? []
: [
{
path: '*',
redirect: '/404',
hidden: true
}
])
}
- 把微应用 layout 部分加上逻辑判断
在微应用中就不显示菜单这些了,当然这里指的是主应用提供菜单的做法
// computed
computed: {
isMicroFrontends() {
return window.__POWERED_BY_QIANKUN__
}
},
// layout
<template v-if="!isMicroFrontends">
// 原本的layout
</template>
<template v-else>
// 去掉layout过后的内容
</template>