vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue微前端项目

创建一个基于Vue的微前端项目完整步骤

作者:筱筱°

微前端是前端web开发的趋势,微服务允许你将后端分解成更小的部分,受此启发,微前端允许你独立构建、测试和部署前端应用,这篇文章主要介绍了如何创建一个基于Vue的微前端项目的完整步骤,需要的朋友可以参考下

创建一个基于 Vue 的微前端项目,以 qiankun(乾坤) 框架为例,从零搭建「主应用 + 子应用」的微前端架构,步骤清晰且可直接落地。

核心前置知识

第一步:环境准备

确保已安装:

第二步:创建主应用(基座应用)

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. 验证效果

第五步:打包部署

打包前先确认:

所有子应用已解决 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;
    }
}

关键注意事项(避坑指南)

  1. 跨域问题: 主 / 子应用都必须配置 Access-Control-Allow-Origin: *,否则子应用无法加载;
  2. 路由冲突:
  1. 样式隔离: 主应用启动 qiankun 时开启 strictStyleIsolation: true,避免子应用样式污染主应用;
  2. 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;
  }
}
  1. 生产环境部署:

总结

  1. 微前端核心:主应用通过 qiankun 注册子应用,子应用暴露 bootstrap/mount/unmount 生命周期;
  2. 关键配置:子应用打包为 umd 格式、主 / 子应用配置跨域、路由适配微前端环境;
  3. 启动顺序:先启动子应用,再启动主应用,验证时先确认子应用独立运行正常。
  4. 子应用打包:需配置 umd 格式 + 生产环境 publicPath + 关闭 sourceMap,执行 npm run build 生成 dist;
  5. 主应用打包:修改子应用 entry 为生产地址,执行 npm run build 生成 dist;
  6. 部署关键:子应用需配置跨域,主 / 子应用分别部署到服务器(如 Nginx),确保路由和静态资源路径正确。

到此这篇关于创建一个基于Vue的微前端项目的文章就介绍到这了,更多相关Vue微前端项目内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文