本文将记录一下从零搭建一个微前端架构系统,技术栈使用qiankun+vite+vue3,后面还会持续分享主应用与微应用通信,组件共享,性能优化等内容,因为qiankun官网没有介绍vite配置的方法,都是基于webpack的,我在使用vite搭建的时候踩了不少坑,也会记录分享在这里。
qiankun官网:介绍 - qiankun
参考网站:Micro Frontends
一、微前端架构介绍
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。 它具有如下特点:
- 技术栈无关。微应用可以是你喜欢的任意技术栈,Vue、React or Angular...
- 独立部署
- 独立运行。微应用之间状态隔离
二、项目搭建与准备
1. 创建主应用和子应用
- 使用
vite
分别创建主应用项目和子应用项目。可以通过npm create vue@latest
命令并按照提示进行相应配置来创建基础的vite
项目。 - 在主应用和子应用中安装
Element Plus
(因为后续会用到,提前先配置好),在项目目录下执行npm install element-plus
,并且按需引入相关组件和样式(可通过自动导入插件等方式实现更便捷的引入)。 - 在主应用中安装
qiankun
,执行npm install qiankun
。
2. 配置主应用
- 在主应用的入口文件(
main.ts
)中,引入并注册Element Plus
组件(假设采用按需引入方式,需先配置好自动导入插件如unplugin-vue-components
和unplugin-auto-import
)。 - 按照
qiankun
的要求配置主应用,主要包括注册子应用、设置生命周期等。
main.ts文件
import './assets/main.css'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import { registerMicroApps, start } from 'qiankun'
const app = createApp(App)
app.use(router)
app.use(ElementPlus)
app.mount('#app')
registerMicroApps(
[
{
name: 'silvia micro app', // app name registered
entry: '//localhost:5174', // 微应用的出口地址
container: '#container', // 微应用挂载的容器id
activeRule: '/silvia-micro', // 微应用激活路由规则
}
]
)
start()
App.vue文件(这里直接在vite创建的App.vue文件写展示子应用的代码)
<div class="wrapper">
<HelloWorld msg="主应用" />
<el-button>ss</el-button>
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/silvia-micro">Micro</RouterLink>
</nav>
<div id="container"></div>
</div>
3. 配置子应用
- 这里遇到了vite搭建qiankun的两个坑(很重要!!!)
- 判断是否为独立运行时问题:官网中使用
window.__POWERED_BY_QIANKUN__
,但是在vite下运行后window下找不到__POWERED_BY_QIANKUN__
, 后来经查阅发现vite要使用插件vite-plugin-qiankun
,安装完成后,使用该插件提供的qiankunWindow.__POWERED_BY_QIANKUN__
来判断。 - 子应用导出相应的生命周期问题:按照官网上导出子应用生命周期的方法,运行后发现在这里打印的log都没有出来,并且还报了个错,最后发现这里也需要
vite-plugin-qiankun
提供的导出方法renderWithQiankun
- 判断是否为独立运行时问题:官网中使用
- webpack下的写法
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
render();
}
export async function bootstrap() {
console.log('[vue] vue app bootstraped');
}
export async function mount(props: QiankunProps | undefined) {
console.log('[vue] props from main framework', props);
render(props);
}
export async function unmount() {
app.unmount();
}
- vite下的写法!(既然我们使用vite搭建的,就得使用这种写法)
// 独立运行时
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render();
}
renderWithQiankun(
{
bootstrap: () => {
console.log('[vue] vue app bootstraped');
},
mount: (props: QiankunProps) => {
console.log('[vue] props from main framework', props);
render(props);
},
unmount: (props: QiankunProps) => {
window.console.log('unmount', props);
app.unmount();
},
update: (props: QiankunProps) => {
window.console.log('update');
}
}
)
- index.html文件中修改挂载点:id需要改成'container'
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<div id="container"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
- 在
vite.config.ts
中添加qiankun
相关配置!(非常重要,否则微应用启动不起来):
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
qiankun('silvia-micro', { useDevMode: true }),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
})
三、项目启动
- 主应用和微应用都
npm run dev
- 打开主应用url,然后点击Micro(我改了vite自动创建完成的按钮名称及跳转的path name),这里遇到了新的问题,微应用加载完又立即走了unmount生命周期
并且还报了
died in status NOT_MOUNTED: Cannot read properties of undefined
这样一个错,打断点跟了一下报错地方,发现原来是子应用没有配置路由。
修改微应用的main.ts文件,导入并挂载路由,完整的代码如下:
import App from './App.vue';
import { createApp } from 'vue';
import router from './router';
import { qiankunWindow, renderWithQiankun, type QiankunProps } from 'vite-plugin-qiankun/dist/helper';
let microRouter = null;
let app: any = null;
function render(props?: QiankunProps) {
microRouter = router;
app = createApp(App);
app.use(microRouter)
app.mount(props?.container ? props?.container.querySelector('#container') : '#container');
}
// 独立运行时
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render();
}
renderWithQiankun(
{
bootstrap: () => {
console.log('[vue] vue app bootstraped');
},
mount: (props: QiankunProps) => {
console.log('[vue] props from main framework', props);
render(props);
},
unmount: (props: QiankunProps) => {
window.console.log('unmount', props);
app.unmount();
microRouter = null;
},
update: (props: QiankunProps) => {
window.console.log('update');
}
}
)
- 接下来再刷新页面,发现不报错了,控制台log也按照我们预期的执行了
基础搭建先写到这里,后面会继续分享主应用与子应用通信方式,组件共享等内容,希望大家持续关注。