# qiankun 微前端

# 核心价值

微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。

# 组成部分

# 主应用

主要功能:

  • 功能上:注册微应用
  • 表现上:作为微应用的 layout,菜单,header 等

# 微应用

修改已有项目为微应用

  • react
  1. 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";
  1. 改造 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")
  );
}
  1. 修改打包方式,和允许跨域
// 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()),
}

  1. 修改路由 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>;
  1. 去掉 404 页面

因为在当前微应用跳转其他微应用时,如果当前微应用有 404 页面,当前微应用以为它自己跳转到了不存在的页面就会出现异常

  1. 把微应用 layout 部分加上逻辑判断

在微应用中就不显示菜单这些了,当然这里指的是主应用提供菜单的做法

{window.__POWERED_BY_QIANKUN__ ? (去掉layout过后的内容):(原本的layout)
  • vue
  1. 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";
  1. 改造 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;
}
  1. 修改打包方式,和允许跨域
// vue.config.js
module.exports = {
  configureWebpack: (config) => {
    config.output = {
      ...config.output,
      library: "vueApp",
      libraryTarget: "umd",
    };
  },
  devServer: {
    headers: {
      "Access-Control-Allow-Origin": "*",
    },
  },
};
  1. 修改路由 mode,与 baseUrl
export default new Router({
  mode: "history",
  base: window.__POWERED_BY_QIANKUN__ ? "/vueApp" : process.env.BASE_URL,
  ...
});

这里的 /vueApp 就是在主应用在注册中使用的 url,主应用遇到 /vueApp 的路由便会去加载当前这个微应用

  1. 给 404 页面加上逻辑判断

因为在当前微应用跳转其他微应用时,如果当前微应用有 404 页面,当前微应用以为它自己跳转到了不存在的页面就会出现异常

{
    ...其他的路由
    ...(window.__POWERED_BY_QIANKUN__
    ? []
    : [
        {
        path: '*',
        redirect: '/404',
        hidden: true
        }
    ])
}
  1. 把微应用 layout 部分加上逻辑判断

在微应用中就不显示菜单这些了,当然这里指的是主应用提供菜单的做法

// computed
computed: {
    isMicroFrontends() {
        return window.__POWERED_BY_QIANKUN__
    }
},
// layout
<template v-if="!isMicroFrontends">
  // 原本的layout
</template>
<template v-else>
  // 去掉layout过后的内容
</template>
lastUpdate: 2/1/2021, 2:41:18 AM