微前端框架--qiankun初探
什么是微前端
Techniques, strategies and recipes for building a modern web app with multiple teams that can ship features independently. –Micro Frontends
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。
微前端架构具备以下几个核心价值:
技术栈无关
主框架不限制接入应用的技术栈,微应用具备完全自主权独立开发、独立部署
微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新增量升级
在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略独立运行时
每个微应用之间状态隔离,运行时状态不共享
微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。
qiankun又是什么
qiankun(乾坤)是一个基于 single-spa 的微前端实现库,旨在帮助大家能更简单、无痛的构建一个生产可用微前端架构系统。qiankun 孵化自蚂蚁金融科技基于微前端架构的云产品统一接入平台。
官方 Example 的使用
clone代码
$ git clone https://github.com/umijs/qiankun.git $ cd qiankun
安装并运行示例程序
$ yarn install $ yarn examples:install $ yarn examples:start
创建qiankun项目
搭建项目结构
- 新建一个
qiankun-examples
空目录:
mkdir qiankun-examples
- 新建主应用入口程序(Vite + Vue3 + TypeScript),项目名称为
app
$ npm create vite@latest
输入命令后,根据提示创建对应的项目,控制台输出如下信息:
✔ Project name: … app
✔ Select a framework: › vue
✔ Select a variant: › vue-ts
- 新建第一个微应用(Webpack + Vue3 + TypeScript),名称叫
home
$ vue create home
根据提示创建好项目即可。
- 再次新建第二个微应用(Webpack + Vue3 + TypeScript),名称叫
profile
$ vue create profile
同样的,根据提示创建好项目即可。
搭建好后,项目目录结构如下所示:
qiankun-examples
├── .editorconfig
├── .gitignore
├── .prettierignore
├── .prettierrc.js
├── app
├── home
└── profile
app
目录是 qiankun 框架的主应用项目,home
和 profile
目录是两个微应用项目(你可以根据实际情况添加 N 多个微应用,并且不限技术栈);.editorconfig
为编辑器配置,.prettierignore
和 .prettierrc.js
为 prettier
代码格式化插件的配置信息,点开头的这几个配置文件不是必要的,根据个人喜好。
主应用安装依赖
项目整体结构搭建完毕后,我们就可以开始集成 qiankun
框架了。
1、在主应用中集成 qiankun
框架
$ cd app
$ npm install qiankun --save
2、在主应用中注册微应用
编辑 app/src/App.vue
文件,代码如下:
<template>
<div>
<div class="main-app">
<span @click="open('/home')">Home</span>
<span>|</span>
<span @click="open('/profile')">Profile</span>
</div>
<div id="subapp-container"></div>
</div>
</template>
<script setup lang="ts">
import { registerMicroApps, start, setDefaultMountApp } from 'qiankun'
// 注册微应用
registerMicroApps([
{
name: 'Home Micro App',
entry: '//localhost:9001',
container: '#subapp-container',
activeRule: '/home'
},
{
name: 'Profile Micro App',
entry: '//localhost:9002',
container: '#subapp-container',
activeRule: '/profile'
}
])
// 设置默认挂载的应用
setDefaultMountApp('/home')
// 启动应用
start()
const open = (path: string): void => {
window.history.replaceState(null, path, path)
}
</script>
配置微应用
微应用虽然不需要额外安装任何其他依赖即可接入 qiankun
主应用,但是需要做一些相关的配置才能与主应用一起工作。
这里只介绍 基于 Vue 的微应用 的接入方式,其他框架的微应用请参考:
1、新建 home/src/public-path.js
文件,并写入如下内容:
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
2、入口文件 main.ts
修改,为了避免根 id #app
与其他的 DOM 冲突,需要限制查找范围,并导出 bootstrap、mount、unmount 三个生命周期钩子,以供主应用在适当的时机调用。
import './public-path'
import * as Vue from 'vue'
import { createRouter, createWebHistory, RouterHistory, Router } from 'vue-router'
import App from './App.vue'
import routes from './router'
import store from './store'
declare global {
interface Window {
__POWERED_BY_QIANKUN__: string | boolean
}
}
let router: Router | undefined = undefined
let instance: Vue.App<Element> | undefined = undefined
let history: RouterHistory | undefined = undefined
function render(props?: { container: HTMLElement | null | undefined }) {
const { container } = props || {}
history = createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/home' : '/')
router = createRouter({
history,
routes
})
instance = Vue.createApp(App)
instance.use(router)
instance.use(store)
instance.mount(container ? (container.querySelector('#app') as HTMLElement) : '#app')
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render()
}
// 导出 bootstrap、mount、unmount 三个生命周期钩子
export async function bootstrap() {
console.log('[vue] vue app bootstraped')
}
export async function mount(props: any) {
console.log('[vue] props from main framework', props)
render(props)
}
export async function unmount() {
instance?.unmount()
instance && instance._container && (instance._container.innerHTML = '')
instance = undefined
router = undefined
history?.destroy()
history = undefined
}
3、修改打包配置(vue.config.js
)
为了便于开发,指定了启动的端口,这样确保项目每次都运行在相同的端口上,并且由于 qiankun
是通过 fetch
去获取微应用的静态资源(图片、js文件等等),所以必须要求这些静态资源支持跨域。
const { name } = require('./package')
module.exports = {
devServer: {
port: 9001, // 指定端口
headers: {
'Access-Control-Allow-Origin': '*' // 配置跨域
}
},
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd', // 把微应用打包成 umd 库格式
jsonpFunction: `webpackJsonp_${name}`
}
}
}
至此,我们的微应用已经配置完毕了;按照如上步骤将 profile
这个微应用也进行修改,并且端口指定为 9002
。
启动项目
经过以上的配置,我们可以把主应用和微应用都跑起来查看效果了,但是每个应用都需要我们 cd xxx && npm run serve
这么操作一遍的话,岂不是累死人,像我们现在只有三个应用还好,如果是十个八个呢,光启动项目都得半天了。所以这里通过 npm-run-all
库来帮我们进行偷懒,一键安装依赖 & 一键运行项目。
- 新建
qiankun-examples/package.json
{
"name": "qiankun-examples",
"version": "1.0.0",
"main": "index.js",
"scripts": {},
"devDependencies": {}
}
- 安装
npm-run-all
$ npm install npm-run-all -D
- 配置
scripts
脚本命令
{
"name": "qiankun-examples",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"install": "npm-run-all --serial install:*",
"start": "npm-run-all --parallel start:*",
"install:app": "cd app && npm install",
"start:app": "cd app && npm run dev",
"install:home": "cd home && npm install",
"start:home": "cd home && npm run serve",
"install:profile": "cd profile && npm install",
"start:profile": "cd profile && npm run serve"
},
"devDependencies": {
"npm-run-all": "^4.1.5"
}
}
- 配置完成,我们可以一键安装依赖和一键启动项目了
$ cd qiankun-examples
$ npm install // 安装 npm-run-all
$ npm run install // 安装主应用和微应用(app/home/profile)的依赖
$ npm run start // 启动主应用和微应用(app/home/profile)项目
项目启动成功后,浏览器访问 http://localhost:5173/
即可看到效果(这个端口是Vite默认的,你根据实际情况访问你的地址即可)。
至此,我们的整个项目搭建就算告一段落了,更多的隐藏技能则需要你自行去探索了(比如:全局数据共享、主应用和微应用之间的数据交互等)。