前后端分离的项目越做越大之后,一个很常见的诉求出现了:同一个仓库里既有面向管理员的 PC 后台,也有给用户用的移动端 H5,还夹杂着几个一次性的营销活动页。这些页面彼此独立、访问路径不同、发布节奏也不同,如果拆成多个仓库,维护成本直线上升;放在一个仓库里用多个入口来构建,就成了更顺手的方案。Vue 3 官方推荐的构建工具 Vite 默认只支持单入口,好在它基于 Rollup 的配置能力非常灵活,通过 rollupOptions.input 就能轻松实现多入口构建。本文从目录规划讲到构建部署,把完整的落地过程过一遍。

一、先想清楚目录结构,多入口项目的一半工作是规划
多入口项目的目录组织方式会直接影响后续的开发体验。常见做法是把每个入口当作一个“小应用”,各自拥有独立的 main.js、App.vue、路由和状态管理,公共的部分则提取到 shared 或者 common 目录里。下面是一个经过实践验证的结构:
vue3-multi-entry/ ├── admin/ # 后台管理入口 │ ├── index.html │ ├── src/ │ │ ├── main.js │ │ ├── App.vue │ │ ├── router/ │ │ └── views/ ├── h5/ # 移动端入口 │ ├── index.html │ └── src/ │ ├── main.js │ ├── App.vue │ └── views/ ├── shared/ # 公共代码 │ ├── components/ │ ├── utils/ │ └── api/ ├── vite.config.js └── package.json
这个结构的好处在于边界清晰:admin 和 h5 两个入口之间没有任何直接引用关系,它们都只依赖 shared 目录。如果某天需要把其中一个入口拆出去独立仓库,只需要把 shared 一起带走就行,迁移成本极低。反过来,如果一开始就把所有代码混在一个 src 里,用文件夹区分入口,时间一长很容易出现 H5 的代码 import 了后台的组件这种跨入口引用,构建配置会越来越乱。
还有一个容易被忽略的点:每个入口的 index.html 要放在各自入口的根目录下,而不是项目的根目录。Vite 在开发阶段会把 HTML 文件当作入口处理,HTML 里引用对应入口的 main.js,这样每个页面天然就是一个独立应用。以 admin 的 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> <script type="module" src="/admin/src/main.js"></script> </body> </html>
注意 script 标签里的路径是绝对路径 /admin/src/main.js,以项目根目录为基准。H5 入口的 HTML 结构完全一样,只是把路径换成 /h5/src/main.js,标题换成自己的即可。
二、vite.config.js 多入口配置的完整写法
核心配置只有一处:在 build.rollupOptions.input 里以对象形式声明所有入口。对象的 key 是入口名,value 是 HTML 文件的路径,这个 key 会直接决定构建产物的目录结构。完整配置如下:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@admin': resolve(__dirname, 'admin/src'),
'@h5': resolve(__dirname, 'h5/src'),
'@shared': resolve(__dirname, 'shared')
}
},
build: {
rollupOptions: {
input: {
admin: resolve(__dirname, 'admin/index.html'),
h5: resolve(__dirname, 'h5/index.html')
},
output: {
// 产物按入口名分目录存放,方便部署时区分
entryFileNames: 'assets/[name]/[name]-[hash].js',
chunkFileNames: 'assets/[name]/[name]-[hash].js'
}
}
}
})
这里的 resolve.alias 配置值得多说一句。给每个入口设置独立的别名,代码里写 import Header from '@shared/components/Header.vue' 比一长串相对路径清爽得多,更重要的是,别名本身就约束了引用方向。团队里可以约定一条规则:admin 内部可以引用 @shared,但绝不允许引用 @h5,反之亦然。有了明确的别名边界,Code Review 时一眼就能看出有没有越界引用。
配置完成后,执行 npx vite build,产物目录大致是这样的:dist/admin/index.html 和 dist/h5/index.html,各自的 JS、CSS 都带上了入口名前缀,公共模块会被 Rollup 自动抽成共享 chunk。部署时只需要把整个 dist 目录扔给 Nginx,配置两条 location 或者直接按目录访问即可。开发阶段更简单,启动 dev server 后直接访问 http://localhost:5173/admin/index.html 和 http://localhost:5173/h5/index.html 就能分别调试两个入口,热更新互不干扰。
三、进阶细节:差异化配置、条件构建与常见坑
真实项目里,两个入口往往有不同的技术诉求。比如 H5 端通常需要做 rem 或 viewport 适配,而后台管理不需要;后台可能要用 CDN 引入体积较大的图表库来减小构建产物。这类差异化可以通过环境变量加条件配置来实现。在 .env.admin 和 .env.h5 中定义各自的变量,然后在 vite.config.js 里按模式切换插件:
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd())
const isH5 = mode === 'h5'
return {
base: isH5 ? '/h5/' : '/',
plugins: [
vue(),
// 仅 H5 模式启用移动端适配插件
...(isH5 ? [require('postcss-px-to-viewport')()] : [])
],
build: {
rollupOptions: {
input: isH5
? { h5: resolve(__dirname, 'h5/index.html') }
: { admin: resolve(__dirname, 'admin/index.html') }
}
}
}
})
配合 package.json 里的脚本 "build:admin": "vite build --mode admin" 和 "build:h5": "vite build --mode h5",就可以按入口单独构建、单独发布。对于发布节奏不一致的团队来说,这种“同仓库、分入口、各自发布”的模式比每次全量构建要安全得多——改了活动页不会牵动后台的发布流程,出问题时回滚范围也更小。
最后提几个实际踩过的坑。第一个是 base 配置:如果 H5 部署在子路径下(比如 https://ippipp.com/h5/),一定要设置 base: '/h5/',否则构建出来的资源引用路径全是绝对路径,页面会白屏。第二个是路由的 history 模式:如果用 createWebHistory,要传入对应的 base 参数,如 createWebHistory('/h5/'),Nginx 端还要配 try_files 把所有路径回落到对应的 index.html。第三个是公共代码的抽取策略:默认情况下 Rollup 会自动提取被多个入口共享的模块,但如果 shared 里的代码只在单入口使用,它会被打进那个入口的 bundle,这是正常行为,不必强行拆分。第四个是 HTML 里的 favicon、meta 等资源,多入口项目里每个 HTML 独立管理即可,不必抽公共模板,Vite 对每个入口的 HTML 处理是完全独立的,加了 vite-plugin-html 之类的模板插件反而增加复杂度。
整体来看,Vite 做多入口构建的核心就一行 rollupOptions.input,真正的功夫花在目录规划、别名约束和部署路径这些工程细节上。把边界定清楚,一个仓库管多个独立应用完全可以跑得又稳又轻。
Vue3多入口Vite多页面配置rollupOptions修改时间:2026-09-12 11:42:45