Vue3 多入口项目实战:如何优雅管理多个独立业务模块

在中大型前端项目中,我们常常会遇到多个独立业务模块并存 的场景(比如企业内部的抽奖系统、会议系统、生日活动系统等)。如果将它们耦合在一个项目中,会导致代码冗余、构建缓慢、维护困难。Vue3 + Vite 的多入口方案可以完美解决这个问题,让每个业务模块都能独立开发、独立部署、独立迭代

为什么需要多入口?

先看一个典型的业务场景:

某公司需要开发以下几个独立的活动系统:

  • 抽奖系统(lottery)
  • 会议系统(meeting)
  • 生日派对系统(birthdayParty)
  • 员工激励系统(ygzj)

这些系统技术栈相同,但业务完全独立,如果做成四个独立项目,会存在重复配置(如路由、状态管理、UI 组件)的问题;如果做成单入口项目,又会导致代码耦合、构建产物过大。

多入口方案的优势

  • 代码复用:公共组件、工具函数、配置可在多个入口间共享。
  • 独立开发:每个入口可单独启动开发服务,互不干扰。
  • 独立部署:每个入口可单独构建,部署到不同的域名或路径。
  • 技术隔离:某个入口的技术迭代(如升级依赖)不会影响其他入口。

第一步: 项目结构设计

先看多入口项目结构:

plaintext 复制代码
src/
├── assets/          # 公共静态资源(图片、字体等)
├── components/      # 公共组件(多个入口共享)
├── packages/        # 业务入口目录
│   ├── lottery/     # 抽奖系统入口
│   │   ├── api/     # 抽奖系统接口
│   │   ├── router/  # 抽奖系统路由
│   │   ├── views/   # 抽奖系统页面
│   │   ├── App.vue  # 抽奖系统根组件
│   │   ├── main.js  # 抽奖系统入口文件
│   │   └── index.html # 抽奖系统HTML模板
│   ├── meeting/     # 会议系统入口(结构同lottery)
│   ├── birthdayParty/ # 生日派对系统入口
│   └── ygzj/        # 员工激励系统入口
├── vite.config.js   # Vite 多入口配置
└── package.json     # 依赖和脚本配置

这种结构的核心是每个入口都有独立的 main.jsApp.vueindex.html ,同时共享 src 下的公共资源和组件。

第二步:Vite 多入口核心配置

Vite 基于 Rollup 打包,多入口的核心是通过 build.rollupOptions.input 指定多个入口文件路径,同时配合 npm 脚本实现「独立开发」和「批量打包」。

完整的 vite.config.js 配置

javascript 复制代码
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'

// 1. 定义所有入口(key:入口名称,value:入口文件路径)
const multiEntries = {
  lottery: path.resolve(__dirname, 'src/packages/lottery/main.js'),
  meeting: path.resolve(__dirname, 'src/packages/meeting/main.js'),
  party: path.resolve(__dirname, 'src/packages/birthdayParty/main.js'),
  ygzj: path.resolve(__dirname, 'src/packages/ygzj/main.js'),
}

export default defineConfig({
  plugins: [vue()],
  // 通用别名配置(方便所有入口引入公共资源,非多入口核心,但必备)
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
      '@assets': path.resolve(__dirname, 'src/assets'),
      '@components': path.resolve(__dirname, 'src/components'),
      '@utils': path.resolve(__dirname, 'src/utils'),
    },
  },
  // 2. 开发服务器配置(支持多入口独立启动的基础)
  server: {
    port: 3000,
    open: false,
    cors: true, // 解决跨域(如果多个入口需要调用同一接口)
  },
  // 3. 多入口核心打包配置(Rollup 选项)
  build: {
    rollupOptions: {
      // 指定多个入口文件(核心!告诉 Vite 要打包哪些入口)
      input: multiEntries,
      // 配置输出规则(每个入口独立输出到对应目录)
      output: {
        // 输出目录:dist/[入口名称]/,如 dist/lottery/、dist/meeting/
        dir: 'dist/[name]',
        // 静态资源文件名格式(添加哈希,避免缓存)
        assetFileNames: 'assets/[name]-[hash][extname]',
        // 代码分割后的chunk文件名
        chunkFileNames: 'assets/[name]-[hash].js',
        // 入口文件文件名
        entryFileNames: 'assets/[name]-[hash].js',
      },
    },
  },
})

关键配置说明:

  • multiEntries:集中管理所有入口路径,方便维护(新增入口只需在这里添加);
  • build.rollupOptions.input:Rollup 的核心配置,指定多个入口文件,Vite 会根据这个配置打包所有入口;
  • output.dir: 'dist/[name]':每个入口的打包产物独立存放在 dist 下的对应子目录([name] 对应 multiEntries 的 key),避免文件冲突。

第三步:配置 npm 脚本(独立开发 / 打包)

package.json 中配置脚本,支持「单独启动某个入口开发服务」和「批量打包所有入口」:

json 复制代码
{
  "scripts": {
    // 独立开发脚本:启动单个入口的开发服务(--open 可自动打开浏览器)
    "dev:lottery": "vite serve src/packages/lottery/ --config ./vite.config.js --open",
    "dev:meeting": "vite serve src/packages/meeting/ --config ./vite.config.js",
    "dev:party": "vite serve src/packages/birthdayParty/ --config ./vite.config.js",
    "dev:ygzj": "vite serve src/packages/ygzj/ --config ./vite.config.js",
    
    // 打包脚本:单独打包某个入口
    "build:lottery": "vite build --config ./vite.config.js --mode production",
    "build:meeting": "vite build --config ./vite.config.js --mode production",
    
    // 批量打包所有入口(执行一次,打包所有在 multiEntries 中定义的入口)
    "build:all": "vite build --config ./vite.config.js --mode production"
  }
}

脚本执行说明:

  • 开发时:执行 npm run dev:lottery,Vite 会以 src/packages/lottery/index.html 为入口,启动开发服务(端口 3000),修改该入口的代码会热更新,不影响其他入口;
  • 打包时:执行 npm run build:all,Vite 会根据 multiEntries 配置,批量打包所有入口到 dist 目录下(如 dist/lotterydist/meeting);
  • 单独打包:执行 npm run build:lottery,只会打包抽奖系统入口(需确保 multiEntries 中包含该入口)。

入口模块的独立开发规范

为了保证多入口项目的可维护性,每个入口模块需要遵循「独立配置、共享公共资源」的原则:

1. 入口文件(main.js):独立初始化 Vue 应用

每个入口的 main.js 负责自己的 Vue 应用初始化(路由、状态管理等),不影响其他入口:

javascript 复制代码
// src/packages/lottery/main.js(抽奖系统入口)
import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 抽奖系统独立路由
import '@assets/styles/common.scss' // 引入公共样式

const app = createApp(App)
app.use(router)
app.mount('#app')

2. HTML 模板(index.html):独立挂载节点

每个入口的 index.html 是独立的 HTML 模板,需指定唯一的挂载节点(通常是 #app),并引入当前入口的 main.js

html 复制代码
<!-- src/packages/lottery/index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>抽奖系统</title> <!-- 每个入口的标题独立 -->
</head>
<body>
  <div id="app"></div>
  <!-- 引入当前入口的 main.js(路径需正确) -->
  <script type="module" src="/src/packages/lottery/main.js"></script>
</body>
</html>

3. 路由配置:独立路由,避免冲突

每个入口的路由独立维护,如需部署到同域名的不同路径,需配置 base 路径:

javascript 复制代码
// src/packages/lottery/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import LotteryHome from '../views/LotteryHome.vue'

const router = createRouter({
  // 部署到同域名的 /lottery 路径时,需配置 base
  history: createWebHistory(import.meta.env.BASE_URL + 'lottery/'),
  routes: [
    { path: '/', component: LotteryHome },
    // 其他路由...
  ]
})

export default router

4. 公共资源复用:统一路径引入

共享的组件、工具函数、静态资源,通过之前配置的别名引入,无需相对路径层级嵌套:

vue

xml 复制代码
<!-- 抽奖系统页面中引入公共组件 -->
<template>
  <CommonButton @click="startDraw">立即抽奖</CommonButton>
</template>

<script setup>
import CommonButton from '@components/CommonButton.vue' // 共享组件
import { throttle } from '@utils/tool.js' // 共享工具函数
</script>

<style scoped>
@import '@assets/styles/common.scss'; // 共享样式变量

.lottery-container {
  background: $primary-color; // 使用共享变量
}
</style>
相关推荐
小左OvO7 小时前
基于百度地图JSAPI Three的城市公交客流可视化(二)——区域客流
前端·javascript·vue.js
小左OvO8 小时前
基于百度地图JSAPI Three的城市公交客流可视化(三)——实时公交
前端·javascript·vue.js
晴殇i10 小时前
尤雨溪创立的 VoidZero 完成 1250 万美元 A 轮融资,加速整合前端工具链生态
前端·vue.js
菜市口的跳脚长颌10 小时前
一个 Vite 打包配置,引发的问题—— global: 'globalThis'
前端·vue.js·vite
胖虎26510 小时前
实现无缝滚动无滚动条的 Element UI 表格(附完整代码)
前端·vue.js
VOLUN11 小时前
Vue3 选择弹窗工厂函数:高效构建可复用数据选择组件
前端·javascript·vue.js
VOLUN11 小时前
Vue3 中 watch 第三个参数怎么用?6 大配置属性 + 场景指南
前端·javascript·vue.js
远山枫谷11 小时前
vue3通信组件学习小记
前端·vue.js
源码站~13 小时前
基于SpringBoot+Vue的健身房管理系统
vue.js·spring boot·后端·毕业设计·前后端分离·管理系统·健身房