微前端(3)qiankun

在各种评价对比,以及咨询大佬之后,决定先试一下乾坤。

qiankun

  1. single-spa + sandbox + import-html-entry
  2. 实现了 js 沙箱以及微应用和主应用的样式隔离,样式的隔离还可以选择严格模式即 shadow DOM;html entry 的方式引入子应用,相比 js entry 极大的降低了应用改造的成本;有静态资源预加载能力;
  3. 提供了通信方案:onGlobalStateChange 实现主应用与微应用、微应用之间的通信。主应用初始化全局状态同时监听 statechange ;微应用同样也可以监听 statechange 和设置 state ,但必须在 mount 中设置;
  4. 使用 qiankun 的时候需要注意必须创建一个 public-path.js 文件,否则所有的静态资源都不能正常获取到;

项目目录

|——common/ # 存放共用的工具库
|——components/ # 存放公共的组件库
|——main-app/ # 存放主应用 main-app 的文件夹
|——child-app/ # 存放微应用 children-app 的文件夹
|——….. #
|——qiankun.conf # 配置文件
|——build.sh # 打包脚本

实验步骤

  1. 基于现有框架,简化一个 base 版本做测试 demo,main-app 代表 UMS,child-app 代表 PLCS 系列中的一个子应用。
  2. 通过 main-app 访问 child-app。

代码实例

主应用中设置挂载 DOM main-app/src/App.vue

1
2
3
4
<template>
<div id="subApp">这里是child app</div>
<router-view />
</template>

主应用中进行注册 main-app/src/main.ts,当 URL 切换到子应用时,加载子应用并渲染到对应 DOM 节点上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { registerMicroApps, start } from 'qiankun'

registerMicroApps(
[
{
name: 'app-demo',
entry: 'http://127.0.0.1:8083',
container: '#subApp',
activeRule: '/app-demo'
}
],
{
beforeLoad: async (app) => {
console.log('before load', app)
document.title = 'child app'
},
beforeMount: [
async (app) => {
console.log('before mount', app.name)
}
]
}
)

start()

子应用(基于vite)使用vite-plugin-qiankun这个插件。修改child-app/vite.config.ts,需要关闭热更新,开启跨域共享。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import qiankun from 'vite-plugin-qiankun'

const useDevMode = true
export default defineConfig({
base: '/',
server: {
port: 8083,
cors: true,
headers: {
'Access-Control-Allow-Origin': '*'
},
hmr: !useDevMode,
},
plugins: [
qiankun('app-demo', {
useDevMode
})
]
})

main-child/src/main.ts 中判断是否是 qiankun 环境,非环境和之前一样渲染,或是在环境中,使用库自带的渲染。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'

let app: VueApp<Element>

if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
app = createApp(App)
app.use(ElementUI, {
locale: zh
})
setupStore(app)
app.use(router).mount('#app')
} else {
renderWithQiankun({
mount(props) {
console.log('--mount')

app = createApp(App)
app.use(ElementUI, {
locale: zh
})
setupStore(app)
app
.use(router)
.mount(
(props.container
? props.container.querySelector('#app')
: document.getElementById('app')) as Element
)
},
bootstrap() {
console.log('--bootstrap')
},
update() {
console.log('--update')
},
unmount() {
console.log('--unmount')
app?.unmount()
}
})
}

Q & A

  1. 按照教程主应用中输入给定的 url,出现 404
    404
  2. #subApp 只能放在 App.vue 中,放在 Layout 里面找不到
  3. 先找到 #subApp,然后把 DOM 元素替换,但是并没有渲染出来子系统
  4. 看官方 demo,猜测需要 build 之后,用服务启动
  5. build 之后,#app 中没有渲染。子应用访问地址和 httpserver 启动的地址有冲突,会自动加上一段(http://127.0.0.1:8082/localhost:8082),除非换个端口启动,不理解 vite.config.ts 中配置应该怎么写?没有渲染是不是因为配置问题。

使用感受

  1. 上手有一定学习成本;(适配成本比较高,工程化、生命周期、静态资源路径、路由等都要做一系列的适配工作)
  2. 当前项目框架需要使用第三方库,如果 qiankun 升级,第三方库必须跟着升级;若出现问题,不方便定位是库的问题还是当前项目使用的问题。使用第三方库增加了一层成本;

附录
乾坤
Vue3 + Vite + qiankun微前端实践


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!