带你从零搭建一个qiankun+vue微前端应用(附源码)

838 阅读5分钟

一、介绍

qiankun是一个基于single-spa的微前端实现库,旨在帮大家更能简单、无痛的构建一个生产可用的微前端架构系统。

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

我们产品现状:

  • 公司某些产品复杂,每次迭代都需测试做大量的测试,测试很难界定测试点。
  • 公司产品可以根据业务形态抽离出微应用,便于维护,否则很多项目将会演变成巨石应用;
  • 公司成立之初的老产品,框架陈旧、代码规范性差、冗余无用代码,很难做迭代,引入新的产品业务形态几乎不可能(新老框架不兼容、升级框架改动较大)。

这些痛点微前端可以帮我们解决。

1、什么是微前端?

微前端是一种多个团队通过独立发布功能的方式来共同构建现代化web应用的技术手段及方法策略。

微前端架构具备以下几个核心价值:

  • 技术栈无关

    主框架不限制接入应用的技术栈,微应用具备完全自主权

  • 独立开发独立部署

    微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新

  • 增量升级

    在面对各种复杂场景时,通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一个非常好的实施渐进式重构的手段和策略

  • 独立运行时

    每个微应用之间状态隔离,运行时状态不共享

2、qiankun的核心设计理念

  • 简单

由于主应用微应用都能做到技术栈无关,qiankun 对于用户而言只是一个类似 jQuery 的库,你需要调用几个 qiankun 的 API 即可完成应用的微前端改造。

同时由于 qiankun 的 HTML entry 及沙箱的设计,使得微应用的接入像使用 iframe 一样简单。同时由于 qiankun 的 HTML entry 及沙箱的设计,使得微应用的接入像使用 iframe 一样简单。

  • 解耦/技术栈无关

微前端的核心目标是将巨石应用拆解成若干可以自治的松耦合微应用,而 qiankun 的诸多设计均是秉持这一原则,如 HTML entry、沙箱、应用间通信等。这样才能确保微应用真正具备 独立开发、独立运行 的能力。

3、为什么不是iframe

4、特性

  • 基于single-spa封装,提供了开箱即用的API
  • 技术栈无关,任何技术栈的应用均可使用/接入
  • HTML Entry接入方式,让你接入微应用像使用iframe一样简单
  • 样式抽离,确保微应用之间互相不干扰
  • JS沙箱机制,确保微应用之间全局变量/事件不冲突
  • 资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度。
  • umi 插件,提供了 @umijs/plugin-qiankun 供 umi 应用一键切换成微前端架构系统。

二、项目实践

1、主应用配置

主应用配置比较简单,不限技术栈,只需提供一个容器DOM,然后注册微应用并start即可。

  • 安装qiankun
yarn add qiankun # 或者 npm i qiankun -S
  • 注册微应用并启动:
import { registerMicroApps, start } from 'qiankun';
const apps = [{
  name: 'vueChild', //子应用的名称,可以自定义
  entry: 'http://127.0.0.1:8083', //子应用的域名,我本地起了两个,主应用端口是8084,微应用是8083
  container: '#vueChild', //承载子应用的容器,在App.vue中增加的一个容器用于挂载子应用内容
  activeRule: '/vueChild', // 被激活的子应用的路由
}]
registerMicroApps(apps); //注册子应用
start(); //启动qiankun
  • app.vue配置
<template>
  <div id="app">
    <nav>
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
      <router-link to="/vueChild">Vue child App</router-link> <!--新增部分-->
    </nav>
    <router-view/>
    <div id="vueChild"></div><!--新增部分,用于承载子应用-->
  </div>
</template>

这样主应用即配置完成。

2、微应用配置

微应用分为有 webpack 构建和无 webpack 构建项目,有 webpack 的微应用(主要是指 Vue、React、Angular)需要做的事情有:

  • 新增 public-path.js 文件,用于修改运行时的 publicPath。

  • 微应用建议使用 history 模式的路由,需要设置路由 base,值和它的 activeRule 是一样的。

  • 在入口文件最顶部引入 public-path.js,修改并导出三个生命周期函数。

  • 修改 webpack 打包,允许开发环境跨域和 umd 打包。

主要的修改就是以上四个,可能会根据项目的不同情况而改变。例如,你的项目是 index.html 和其他的所有文件分开部署的,说明你们已经将构建时的 publicPath 设置为了完整路径,则不用修改运行时的 publicPath (第一步操作可省)。

无 webpack 构建的微应用直接将 lifecycles 挂载到 window 上即可。

以下以Vue微应用配置为例实现配置:

(1)、在 src 目录新增 public-path.js:

if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

(2)、路由配置更改

// src/router/index.js
Vue.use(VueRouter)

const routes = [
  // ......
]

const router = new VueRouter({
  mode: 'history',
  base: window.__POWERED_BY_QIANKUN__ ? '/vueChild' : '/', // vueChild即是在主应用中被激活的子应用的路由
  routes
})
export default router

(3)、入口文件 main.js 修改,为了避免根 id #app 与其他的 DOM 冲突,需要限制查找范围。

let instance = null;
function render(props = {}) {
  const { container } = props;
  instance = new Vue({
    router,
    render: (h) => h(App),
  }).$mount(container ? container.querySelector("#app") : "#app"); // 避免根 id #app 与其他的 DOM 冲突,需要限制查找范围
}

export async function mount(props) {
  console.log("[vue] props from main framework", props);
  render(props);
}

//如果是独立运行window.__POWERED_BY_QIANKUN__=undefined
if (!window.__POWERED_BY_QIANKUN__) {
    render()
}

//如果是独立运行window.__POWERED_BY_QIANKUN__=undefined
if (!window.__POWERED_BY_QIANKUN__) {
    render()
}

//最后暴露的三个方法是固定的,加载渲染以及销毁
export async function bootstrap() {}

export async function unmount() {
    instance.$destroy();
}
export async function update(props) {
    //   console.log('update props', props);
}

(3)、修改webpack配置

const { name } = require("./package");
{
    devServer: {
    port: 8083, //这里的端口是必须和父应用配置的子应用端口一致
    headers: {
      "Access-Control-Allow-Origin": "*"
    }
  },
  configureWebpack: {
    output: {
      library: `${name}-[name]`,
      libraryTarget: "umd", // 把微应用打包成 umd 库格式
      chunkLoadingGlobal: `webpackJsonp_${name}`,
    },
  }
}

以上就是vue微应用的配置,React、angular、非webpack的配置详细参考

三、演示

微应用演示.gif

四、源码地址

qiankun-main
qiankun-child