创建一个基于Vue的微前端项目完整步骤
作者:筱筱°
创建一个基于 Vue 的微前端项目,以 qiankun(乾坤) 框架为例,从零搭建「主应用 + 子应用」的微前端架构,步骤清晰且可直接落地。
核心前置知识
- 微前端核心:将多个独立的 Vue 应用(子应用)嵌入到一个主应用中,实现独立开发、独立部署、整体集成。
- 技术选型:主应用(Vue 3) + 子应用(Vue 3) + qiankun(微前端框架),兼容 Vue 2(只需微调配置)。
第一步:环境准备
确保已安装:
- Node.js ≥ 14.18.0
- npm/yarn/pnpm(推荐 npm)
- @vue/cli ≥ 5.0.0(vue --version 验证)
第二步:创建主应用(基座应用)
1. 创建并初始化主应用
# 创建主应用(命名为 main-app) vue create main-app # 选择 Vue 3 + Default 模板(回车确认) cd main-app # 安装 qiankun npm install qiankun -S npm install vue-router -S
2. 配置主应用核心代码
(1)修改主应用入口文件 src/main.js
import { createApp } from 'vue'
import { registerMicroApps, start, setDefaultMountApp } from 'qiankun'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router).mount('#app')
// 注册子应用
registerMicroApps([
{
name: 'vue-sub-app', // 子应用唯一标识(需和子应用 package.json name 一致)
entry: '//localhost:8081', // 子应用运行地址
// entry: '/vue-sub-app/', // 子应用运行地址
container: '#sub-app-container', // 子应用挂载的 DOM 容器(需在 App.vue 中定义)
activeRule: '/vue-sub-app', // 触发子应用激活的路由规则
},
])
// 设置默认应用(可选,打开页面默认加载主应用)
setDefaultMountApp('/');
// 启动 qiankun
start({
sandbox: { strictStyleIsolation: true }, // 开启样式隔离,避免子应用样式污染主应用
})
(2)修改主应用根组件 src/App.vue
<template>
<div id="app">
<h1>Vue 微前端主应用</h1>
<!-- 主应用导航 -->
<nav>
<router-link to="/">主应用首页</router-link> |
<router-link to="/vue-sub-app">子应用</router-link>
</nav>
<!-- 子应用挂载容器 -->
<div id="sub-app-container"></div>
</div>
</template>
<style scoped>
nav {
margin: 20px 0;
}
a {
margin-right: 10px;
text-decoration: none;
color: #409eff;
}
</style>
(3)修改主应用路由 src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const routes = [
{
path: '/',
name: 'home',
component: HomeView,
// component: () => import('@/views/HomeView'),
},
// 新增:子应用路由占位(必须和 activeRule 匹配,且不能有 component)
{
path: '/vue-sub-app/*', // 通配符匹配子应用所有路由
name: 'vue-sub-app',
},
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
})
export default router
(4)配置主应用端口(避免和子应用冲突)
在主应用根目录创建 vue.config.js:
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
devServer: {
port: 8080, // 主应用运行在 8080 端口
headers: {
'Access-Control-Allow-Origin': '*', // 允许跨域(子应用加载必需)
},
},
})
第三步:创建子应用(Vue 子应用)
1. 创建并初始化子应用
# 回到上级目录,创建子应用(命名为 vue-sub-app) cd .. vue create vue-sub-app # 选择 Vue 3 + Default 模板 cd vue-sub-app npm install vue-router -S
2. 配置子应用核心代码
(1)修改子应用入口文件 src/main.js
import '../public-path'; // 必须放在最顶部!(解决路由懒加载的 chunk 路径解析问题)
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
let app = null
// 微前端环境下的挂载函数
function render(props = {}) {
const { container } = props
// 挂载容器:微前端环境用主应用提供的容器,否则用默认 #app
const mountNode = container ? container.querySelector('#app') : '#app'
app = createApp(App)
app.use(router).mount(mountNode)
}
// 独立运行时直接挂载
if (!window.__POWERED_BY_QIANKUN__) {
render()
}
// 微前端生命周期:子应用必须暴露这三个函数
export async function bootstrap() {
console.log('vue-sub-app bootstrap')
}
export async function mount(props) {
console.log('vue-sub-app mount')
render(props)
}
export async function unmount() {
console.log('vue-sub-app unmount')
app.unmount() // 卸载应用
app = null
}
(2)修改子应用路由 src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
// 微前端环境下,路由基础路径要和主应用的 activeRule 一致
const base = window.__POWERED_BY_QIANKUN__ ? '/vue-sub-app' : process.env.BASE_URL
const routes = [
{
path: '/',
name: 'home',
component: HomeView,
},
{
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue'),
},
]
const router = createRouter({
history: createWebHistory(base), // 动态设置基础路径
routes,
})
export default router
(3)配置子应用打包和跨域
在子应用根目录创建 vue.config.js:
const { defineConfig } = require('@vue/cli-service')
const { name } = require('./package.json')
module.exports = defineConfig({
devServer: {
port: 8081, // 子应用运行在 8081 端口
headers: {
'Access-Control-Allow-Origin': '*', // 允许跨域
},
},
// 配置打包为 umd 格式(qiankun 要求)
configureWebpack: {
output: {
library: `${name}-[name]`,
libraryTarget: 'umd', // 关键:输出为 umd 模块
chunkLoadingGlobal: `webpackJsonp_${name}`,
},
},
})
(4)解决子应用路由懒加载的 chunk 路径问题
// vue-sub-app/public-path.js
// 微前端环境下,动态设置 publicPath 为子应用的 entry 地址
if (window.__POWERED_BY_QIANKUN__) {
// __INJECTED_PUBLIC_PATH_BY_QIANKUN__ 是 qiankun 自动注入的子应用 entry 地址(如 //localhost:8081/)
// 忽略 __webpack_public_path__ 的 ESLint 未定义校验
/* eslint-disable-next-line no-undef */
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
} else {
// 独立运行时,publicPath 为根路径
/* eslint-disable-next-line no-undef */
__webpack_public_path__ = process.env.BASE_URL;
}
第四步:启动并验证微前端
1. 启动子应用
cd vue-sub-app npm run serve # 验证:访问 http://localhost:8081 能看到子应用独立运行
2. 启动主应用
cd ../main-app npm run serve # 访问 http://localhost:8080
3. 验证效果
- 访问 http://localhost:8080:看到主应用首页;
- 点击「子应用」链接:页面跳转到 /vue-sub-app,子应用成功嵌入主应用;
- 子应用内点击「About」:子应用路由正常跳转,主应用布局保持不变。
第五步:打包部署
打包前先确认:
所有子应用已解决 ChunkLoadError、unmount is not a function 等运行时错误;
主 / 子应用的 vue.config.js 配置符合微前端要求(跨域、umd 打包、publicPath 等)。
1. 子应用打包(关键,需适配微前端)
(1)子应用打包前的配置检查(必做)
确保子应用 vue.config.js 包含以下配置(适配微前端打包):
// vue-sub-app/vue.config.js
const { defineConfig } = require('@vue/cli-service')
const { name } = require('./package.json')
module.exports = defineConfig({
// 生产环境关闭 sourceMap(减小体积,避免泄露源码)
productionSourceMap: false,
// 打包输出目录(默认 dist,可自定义)
outputDir: 'dist',
// 关键:静态资源路径(生产环境需配置为子应用部署地址,如 "/sub-app/" 或完整域名)
publicPath: process.env.NODE_ENV === 'production'
? 'https://your-sub-app-domain.com/' // 子应用生产部署地址(必填)
// ? '/vue-sub-app/' // 子应用生产部署地址(必填)
: '/',
configureWebpack: {
output: {
// 微前端要求打包为 umd 格式
library: `${name}-[name]`,
libraryTarget: 'umd',
chunkLoadingGlobal: `webpackJsonp_${name}`,
}
}
})
(2)子应用执行打包命令
打开子应用根目录终端,执行:
npm run build # 或 yarn build / pnpm build
执行完成后,子应用根目录会生成 dist 文件夹,这是子应用的生产包
(3)子应用打包注意事项
publicPath 配置: 生产环境的 publicPath 必须是子应用的实际部署地址(如 https://sub-app.example.com/ 或 /vue-sub-app/),否则 chunk 文件会加载失败;
打包产物: dist 文件夹包含子应用的所有静态资源(JS/CSS/ 图片),需部署到服务器(如 Nginx、OSS 等)。
2. 主应用打包
(1)主应用打包前的配置调整
修改主应用 src/main.js,将子应用的 entry 从开发环境的本地地址改为生产环境地址:
// main-app/src/main.js
import { createApp } from 'vue'
import { registerMicroApps, start } from 'qiankun'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router).mount('#app')
// 核心修改:entry 改为子应用生产部署地址
registerMicroApps([
{
name: 'vue-sub-app', // 必须和子应用 package.json 的 name 一致
entry: 'https://your-sub-app-domain.com/', // 子应用生产地址(如 Nginx 部署地址)
// entry: '/vue-sub-app/', // 子应用运行地址
container: '#sub-app-container',
activeRule: '/vue-sub-app', // 激活规则不变
},
])
start({
sandbox: { strictStyleIsolation: true },
})
修改主应用 vue.config.js(按需配置):
// main-app/vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
productionSourceMap: false,
outputDir: 'dist',
// 主应用的 publicPath,部署在根路径则为 '/',子路径则为 '/main-app/'
publicPath: '/',
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
}
}
})
(2)主应用执行打包命令
打开主应用根目录终端,执行:
npm run build # 或 yarn build / pnpm build
3. 打包后的部署(以 Nginx 为例)
(1)子应用部署
将子应用 dist 文件夹上传到 Nginx 的指定目录(如 /nginx/html/vue-sub-app),修改 Nginx 配置:
# nginx.conf
server {
listen 80;
server_name sub-app.example.com; # 子应用域名
# 子应用静态资源目录
root /nginx/html/vue-sub-app;
index index.html;
# 允许跨域(主应用加载子应用必需)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Allow-Headers *;
# 解决 history 模式路由刷新 404
location / {
# root html/vue-sub-app;
try_files $uri $uri/ /index.html;
}
}
(2)主应用部署
将主应用 dist 文件夹上传到 Nginx 根目录(如 /nginx/html),修改 Nginx 配置:
# nginx.conf
server {
listen 80;
server_name main-app.example.com; # 主应用域名
root /nginx/html;
index index.html;
# 解决主应用 history 模式路由刷新 404
location / {
# root html/main-app;
try_files $uri $uri/ /index.html;
}
# 可选:如果主应用和子应用部署在同一域名的不同路径
# location /vue-sub-app/ {
# proxy_pass http://sub-app.example.com/;
# }
}
(3)主应用和子应用部署在同一域名的不同路径
server {
listen 8002;
server_name localhost;
# ========== 1. 主应用:访问 http://localhost:8002/ ==========
location / {
root html/main; # 主应用文件目录(Nginx安装目录下的 html/main)
index index.html; # 主应用入口文件
# 前端路由兼容:刷新不404(Vue/React/Angular必配)
try_files $uri $uri/ /index.html;
}
# ========== 2. 子应用1:访问 http://localhost:8002/sub/ ==========
location /sub/ {
root html; # 根目录为html,最终路径是 html/sub
index index.html; # 这里无需写 sub/index.html,root已包含sub
# 回退到主应用 index.html,而非 /sub/index.html(进入子应用)
try_files $uri $uri/ /index.html;
# 可选:强制添加末尾斜杠,避免 /sub 访问异常
rewrite ^/sub$ /sub/ permanent;
}
# ========== 3. 子应用2:访问 http://localhost:8002/child/ ==========
location /child/ {
root html;
index index.html;
try_files $uri $uri/ /index.html;
rewrite ^/child$ /child/ permanent;
}
# 允许跨域(主应用加载子应用必需)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Allow-Headers *;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
关键注意事项(避坑指南)
- 跨域问题: 主 / 子应用都必须配置 Access-Control-Allow-Origin: *,否则子应用无法加载;
- 路由冲突:
- 主应用路由需添加子应用的通配符路由(/vue-sub-app/*);
- 子应用路由基础路径要适配微前端环境(window.POWERED_BY_QIANKUN);
- 样式隔离: 主应用启动 qiankun 时开启 strictStyleIsolation: true,避免子应用样式污染主应用;
- Vue 2 适配:
子应用 main.js 中替换为 Vue 2 的写法:
import '../public-path'; // 必须放在最顶部!(解决路由懒加载的 chunk 路径解析问题)
import Vue from 'vue'
import App from './App.vue'
import router from './router'
let app = null
function render(props = {}) {
const { container } = props
app = new Vue({
router,
render: h => h(App)
}).$mount(container ? container.querySelector('#app') : '#app')
}
// 独立运行时直接挂载
if (!window.__POWERED_BY_QIANKUN__) {
render()
}
// 微前端生命周期:子应用必须暴露这三个函数
export async function bootstrap() {
console.log('vue-sub-app bootstrap')
}
export async function mount(props) {
console.log('vue-sub-app mount')
render(props)
}
export async function unmount() {
console.log('vue-sub-app unmount')
// Vue 2 正确卸载方法:销毁实例 + 清空 DOM
if (app) {
app.$destroy(); // 销毁 Vue 实例
// 清空 DOM 内容(避免残留)
app.$el.innerHTML = '';
app = null;
}
}
- 生产环境部署:
- 子应用需打包为 umd 格式(已配置);
- 主应用 registerMicroApps 中 entry 改为子应用的生产环境地址(如
https://sub-app.example.com)。
总结
- 微前端核心:主应用通过 qiankun 注册子应用,子应用暴露 bootstrap/mount/unmount 生命周期;
- 关键配置:子应用打包为 umd 格式、主 / 子应用配置跨域、路由适配微前端环境;
- 启动顺序:先启动子应用,再启动主应用,验证时先确认子应用独立运行正常。
- 子应用打包:需配置 umd 格式 + 生产环境 publicPath + 关闭 sourceMap,执行 npm run build 生成 dist;
- 主应用打包:修改子应用 entry 为生产地址,执行 npm run build 生成 dist;
- 部署关键:子应用需配置跨域,主 / 子应用分别部署到服务器(如 Nginx),确保路由和静态资源路径正确。
到此这篇关于创建一个基于Vue的微前端项目的文章就介绍到这了,更多相关Vue微前端项目内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
