⚡vue3+ts+qiankun的微前端快速上手

10,527 阅读3分钟

技术栈:vue3、typescript、qiankun(阿里的微前端框架)、vue-cli4

PS: 一开始打算用vite2,但是调研后发现绝大多少微前端解决方案(包括qiankun)打包策略都是基于webpack的,vite2基本上除了官方文档,没有什么实战文章,更别说微前端的解决方案了(vite2这个工具不像vue-cli4,已经完全抛弃了webpack)。

最近正在设计微前端项目,发现qiankun的官方文档只有vue2.x的写法,没有vue3.x的,刚好把踩完坑的demo分享出来

目录

这里我会把主应用和微应用的目录贴出来,方便大家更直观清晰的理解后面的文件引入关系

PS: 我已经删掉了不涉及微前端功能的目录,看上去更简洁

主应用

parent
 ├── package.json
 └── src
     ├── App.vue
     ├── main.ts
     ├── modules
     │   ├── apps.ts
     │   └── index.ts
     ├── router
     │   └── index.ts
     └── views
         ├── About.vue
         └── Home.vue

微应用

children
 ├── package.json
 ├── vue.config.js
 └── src
     ├── App.vue
     ├── main.ts
     ├── public-path.ts
     ├── router
     │   └── index.ts
     └── views
         ├── About.vue
         └── Home.vue

构建主应用

安装qiankun

yarn add qiankun
或者
npm i qiankun -S

创建modules

在src目录下新建modules目录,modules目录主要用于存放qiankun模块的相关代码

在modules目录下新建apps.ts文件

apps.ts文件用于统一存放微应用的信息

// src/modules/apps.ts
const apps: any[] = [
  {
    name: 'children',
    entry: '//localhost:10001',
    container: '#frame',
    activeRule: '/children',
  },
];

export default apps;

在modules目录下新建index.ts

index.ts目录用于配置、注册主应用及微应用

// src/modules/index.ts
import {
  registerMicroApps,
  addGlobalUncaughtErrorHandler,
  start,
} from 'qiankun';

// 微应用的信息
import apps from './apps';

/**
 * 注册微应用
 * 第一个参数 - 微应用的注册信息
 * 第二个参数 - 全局生命周期钩子
 */
registerMicroApps(apps, {
  // qiankun 生命周期钩子 - 微应用加载前
  beforeLoad: (app: any) => {
    // 加载微应用前,加载进度条
    console.log('before load', app.name);
    return Promise.resolve();
  },
  // qiankun 生命周期钩子 - 微应用挂载后
  afterMount: (app: any) => {
    // 加载微应用前,进度条加载完成
    console.log('after mount', app.name);
    return Promise.resolve();
  },
});

/**
 * 添加全局的未捕获异常处理器
 */
addGlobalUncaughtErrorHandler((event: Event | string) => {
  console.error(event);
});

// 导出 qiankun 的启动函数
export default start;

改动main.ts

将modules中的index.ts引入到main.ts中,并执行start

import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import start from './modules';

const app = createApp(App);

start();

app
  .use(store)
  .use(router)
  .mount('#app');

App.vue

注意,modules/apps中的此处的微应用信息中,有个字段是container,是用于设定微应用挂载节点的,要注意与下方<div id="frame"></div>中的id保持一致(当然,你也可以根据自己需求自己写)

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

至此,主应用的项目代码已经修改完毕。

构建微应用

新增public-path.ts

src 目录下新增 public-path.ts

// src/public-path.ts
if ((window as any).__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = (window as any).__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

改写main.ts

本次主应用、微应用用的vue-router皆为4.0版本,与之前的3.x存在一定的差异

因qiankun是根据路由进行匹配微应用的,因此最好给微应用的路由配置加上base: /微应用名称/,而在vue-router@4中的写法则为createWebHistory('/微应用名称/'),

import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
import { routes } from './router'
import store from './store'
import './public-path';
const APP_NAME = require('../package.json').name;

const app = createApp(App);

let router = null;
function render(props: any) {
  const { container } = props;
  router = createRouter({
    history: createWebHistory(`/${APP_NAME}/`),
    routes
  })

  app.use(store)
  .use(router)
  .mount(container ? container.querySelector('#app') : '#app')
}

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


/**
 * bootstrap : 在微应用初始化的时候调用一次,之后的生命周期里不再调用
 */
export async function bootstrap() {
  console.log('bootstrap');
}

/**
 * mount : 在应用每次进入时调用 
 */
export async function mount(props: any) {
  console.log('mount', props);
  render(props);
}

/**
 * unmount :应用每次 切出/卸载 均会调用
 */
export async function unmount() {
  console.log('unmount');
  app.unmount();
}

vue.config.js

const APP_NAME = require('./package.json').name;
const path = require("path");

module.exports = {
  devServer: {
    // 监听端口
    port: 10001,
    // 关闭主机检查,使微应用可以被 fetch
    disableHostCheck: true,
    // 配置跨域请求头,解决开发环境的跨域问题
    headers: {
      "Access-Control-Allow-Origin": "*",
    },
  },
  configureWebpack: {
    resolve: {
      alias: {
        "@": path.resolve(__dirname, "src"),
      },
    },
    output: {
      // 微应用的包名,这里与主应用中注册的微应用名称一致
      library: APP_NAME,
      // 将你的 library 暴露为所有的模块定义下都可运行的方式
      libraryTarget: "umd",
      // 按需加载相关,设置为 webpackJsonp_微应用名称 即可
      jsonpFunction: `webpackJsonp_${APP_NAME}`,
    },
  },
};

package.json

{
    "name": "children"
}

至此微应用的代码部分也改造完成

运行

在主应用、微应用的目录下,均运行yarn serve 启动项目

此时打开主应用的地址 localhost:8080

在看到能正常显示后,将地址改为localhost:8080/children即可看到微应用被加载进来

结尾

这次分享的内容仅仅是在vue3的版本下如何快速上手qiankun框架, 更细致或更深入的内容建议查阅文档。 如果关于这篇分享有什么疑问的话,可以在下面的评论区告诉我哦,我会尽量解答的(大概吧🙈)

更新

  1. 2021/07/10
    • 将文章中的微应用的名称均统一为children, 涉及主应用的modules/apps、微应用的package.json、微应用的main.ts里的路由base: /微应用名称/,避免出现无法正确加载的问题(因为demo被我改过多版,导致在敲文章的时候有的地方写了children,有的写了child,直接copy我代码的话可能会出现加载不到对应资源的情况, 怪我怪我😭)

QQ图片20210421150857.jpg