qiankun-浅浅体验一把

192 阅读3分钟

前言

前段时间在刷文章的时候偶然看到了 “微前端” ,于是一时起兴便浅浅的体验一把~嗨嗨嗨。

废话不多说直接上菜!!!(概念那些可以前往qiankun官网阅读);

是的,本次体验的微前端方案就是 qiankun

注:只是简单体验了一把(最最最最基础的东西)!!!

实践

本次实践中会用到三个项目,并且这三个项目都是Vue2项目(没有任何限制,也可以用react等等项目),为什么需要三个项目呢?一个项目用来做主应用,剩下两个则是用作子应用(分应用、微应用)(个人认为)。

ok,相信到这还是懵懵的,我也是,嘿嘿。那么主应用、子应用分别是用来干什么的呢?

主应用: 我的理解是将所有子应用聚集在一起,使用统一路由管理子应用,只需要通过主应用的路由就可以访问到每个子应用;

子应用: 我的理解是一个大系统中的很多个小系统(小模块),可以独立开发与其他子系统互不干扰,并且每个子系统可以完全使用不同的技术栈进行开发,比如:A子系统使用Vue,B子系统使用React进行开发;

创建项目

  • 创建主应用项目

    vue create micro-main
    
  • 创建第一个子应用项目

    vue create micro-first-app
    
  • 创建第二个子应用项目

    vue create micro-second-app
    

搭建主应用(micro-main)

  • 安装 qiankun

    npm i qiankun -S
    
  • 在App.vue中创建容器(显示子应用的容器)

    <template>
      <div id="app">
        <!-- 第一个子应用显示的容器 -->
        <div id="first-app"></div>
        <!-- 第二个子应用显示的容器 -->
        <div id="second-app"></div>
      </div>
    </template>
    

    注意:一个应用一个容器来进行展示!!!

  • 注册子应用

    使用 qiankun 提供的 registerMicroApps 方法对所有子应用进行注册

    <script>
    import { registerMicroApps, start } from 'qiankun'
    export default {
        name: 'App',
        created() {
            registerMicroApps([
              {
                name: "FirstApp",
                entry: "//localhost:8888",
                container: "#first-app",
                activeRule: "/first",
              },
              {
                name: "SecondApp",
                entry: "//localhost:8889",
                container: "#second-app",
                activeRule: "/second",
              },
            ]);
        },
        mounted() {
            start();
        },
    }
    </script>
    

    注意:mounted 周期调用 start 函数,注意不要重复调用

搭建子应用(micro-first-app、micro-second-app)

  • src目录下创建 public-path.js 并在 main.js 中导入

    public-path.js:

    /* eslint-disable */
    if (window.__POWERED_BY_QIANKUN__) {
      __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
    }
    

    main.js:

    import "./public-path";
    
  • 导出相应的生命钩子函数,供主应用在适当的时机调用

    main.js

    let instance = null;
    function render(props = {}) {
      const { container } = props;
    
      instance = new Vue({
        router,
        store,
        render: (h) => h(App),
      }).$mount(
        container ? container.querySelector("#first-child") : "#first-child"
      );
    }
    
    // 独立运行时
    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);
      render(props);
    }
    export async function unmount() {
      instance.$destroy();
      instance.$el.innerHTML = "";
      instance = null;
      router = null;
    }
    
  • 修改 vue-router 的 base 路由根路径

    router/index.js

    import Vue from "vue";
    import VueRouter from "vue-router";
    
    Vue.use(VueRouter);
    
    const routes = [];
    
    const router = new VueRouter({
      mode: "history",
      base: window.__POWERED_BY_QIANKUN__ ? "/first-chold/" : "/",
      routes,
    });
    
    export default router;
    
  • 修改服务器端口以及跨域添加请求头和webpack导出配置

    vue.config.js

    // vue.config.js
    const packageName = require("./package.json").name;
    
    module.exports = {
      devServer: {
        port: 8888,
        headers: {
          "Access-Control-Allow-Origin": "*",
        },
      },
      configureWebpack: {
        output: {
          library: `${packageName}-[name]`,
          libraryTarget: "umd",
          jsonpFunction: `webpackJsonp_${packageName}`,
        },
      },
    };
    
  • 修改 public/index.html 挂载容器的 id

    <div id="first-app"></div>
    

    注意:这里的 id 一定要与 main.js 中的 $mount 的参数对应上

  • 修改App.vue

    <template>
      <div id="app">
        <h1>First App</h1>
      </div>
    </template>
    

micro-second-app 的配置同上,只需要将 index.html 的 容器 id 以及 main.js 中的 $mount 的参数 改为 second-app,还有开发服务器端口改成不一样即可。

展示!!!

浏览器访问主应用 开发服务器 地址 并 路径拼接上 activeRule

http://localhost:8081/first

image.png

http://localhost:8081/second

image.png

主应用的 路由组件 内注册展示子应用

  • 创建组件

    image.png

  • 在路由组件中注册子应用

    <template>
      <div calss="child-container">
        <!-- 第一个子应用显示的容器 -->
        <div id="first-app"></div>
        <!-- 第二个子应用显示的容器 -->
        <div id="second-app"></div>
      </div>
    </template>
    <script>
    import { registerMicroApps, start } from "qiankun";
    
    export default {
      name: "ChildApp",
      created() {
        registerMicroApps([
          {
            name: "FirstApp",
            entry: "//localhost:8888",
            container: "#first-app",
            activeRule: "/child-app/first",
          },
          {
            name: "SecondApp",
            entry: "//localhost:8889",
            container: "#second-app",
            activeRule: "/child-app/second",
          },
        ]);
      },
      mounted() {
        start();
      },
    };
    </script>
    

    注意: activeRule需要加上路由配置中注册子应用组件对应的路由的path;

  • 配置组件对应路由 router/index.js

    const routes = [
      {
        path: "/child-app/*",
        name: "ChildApp",
        component: ChildApp,
      },
    ];
    

    注意:一定要在 path 后面加上 *,* 表示/child-app/后接任意字符都匹配到ChildApp组件;

  • 修改App.vue

    <template>
      <div id="app">
        <router-view />
      </div>
    </template>
    

再次展示!!!

http://localhost:8081/child-app/first

image.png

http://localhost:8081/child-app/second

image.png

撤!!!

640.gif