阅读视图

发现新文章,点击刷新页面。

一个 3.5k Star Vue H5 项目的二次进化:我把它重构成了 Monorepo 工程体系

前言

在实际的移动端开发中,我们经常面临这些痛点:

  • 多个 H5 项目,各自为战 — 每个项目独立一套配置,Lint、TypeScript、Vite 各玩各的
  • UI 框架选型难 — NutUI、Vant、Varlet 各有优势,不同业务场景想用不同 UI
  • Mock 接口重复写 — 每个项目写一套 Mock,费时费力
  • 新建项目成本高 — 每次复制粘贴、改配置、接路由,至少半天

Vue H5 Template 就是为解决这些问题而生的。它是一个基于 Turborepo + Vue 3 + TypeScript 的移动端 Monorepo 模板,提供三套 UI 框架版本,共享一切可以共享的东西。


技术栈一览

技术 版本 说明
Vue 3.5 Composition API + <script setup>
TypeScript 6.0 全量覆盖,严格模式
Vite 8.0 构建工具,共享配置
Turborepo 2.9 Monorepo 管理 + 缓存加速
pnpm 10.27 包管理器,workspace + catalog 协议
Pinia 3.0 状态管理 + 持久化 + AES 加密
Vue Router 5.0 路由管理 + NProgress 进度条
Vue I18n 11.3 国际化(简/繁/英/日/港)
Nitro 2.x Mock 后端服务
NutUI / Vant / Varlet 三套并存 三套移动端 UI 框架

项目结构

vue-h5-template/
├── apps/                     # 📱 应用目录
│   ├── h5-nutui/             # NutUI 版 H5(端口 5777)
│   ├── h5-vant/              # Vant 版 H5(端口 5778)
│   ├── h5-varlet/            # Varlet 版 H5(端口 5779)
│   └── backend-mock/         # Nitro Mock 后端(端口 5320)
├── packages/                 # 📦 共享包
│   ├── @core/                # 核心包(设计系统、composables、偏好设置)
│   ├── stores/               # Pinia 状态管理
│   ├── styles/               # 全局样式 + 各 UI 主题
│   ├── locales/              # 国际化语言包
│   └── utils/                # 工具函数(含 NProgress)
├── internal/                 # 🔧 内部配置
│   ├── vite-config/          # 共享 Vite 配置工厂
│   ├── tsconfig/             # 共享 TypeScript 配置
│   └── lint-configs/         # ESLint/Prettier/Stylelint/Commitlint
├── scripts/                  # 🛠️ CLI 工具
│   ├── vsh/                  # 项目 CLI(lint、创建应用等)
│   └── turbo-run/            # 交互式选择运行
└── docs/                     # 📖 多语言文档站(VitePress)

核心亮点

1. 三套 UI 框架,统一架构

项目同时支持 NutUI(京东风格)、Vant(有赞风格)、Varlet(Material Design)三套移动端 UI 框架:

apps/
├── h5-nutui/    → NutUI 4.3,适合电商类场景
├── h5-vant/     → Vant 4.9,适合通用 H5
└── h5-varlet/   → Varlet 3.12,适合 Material 风格

每个应用独立运行,共享路由结构、API 层、状态管理和国际化方案。切换 UI 框架只是换个 app 目录,核心逻辑一行不改。

三个 app 均按需自动导入,不需要手写 import:

// vite.config.ts 只需声明 UI 库类型
export default defineConfig(async () => ({
  application: { uiLibrary: "vant" }, // 'nut' | 'vant' | 'varlet'
  vite: {
    /* 自定义配置 */
  },
}));

剩下的 Resolver、auto-import、组件注册,全部由 @vh5/vite-config 自动处理。


2. 一键创建新应用

内置 create-app CLI,一行命令创建新 H5 应用:

pnpm create-app

交互式选择 UI 框架和应用名,自动生成:

  • 完整的项目结构(路由、视图、API、状态管理)
  • Vite 配置(含 Mock 代理和路径别名)
  • TypeScript 配置(继承共享 tsconfig)
  • 国际化支持(接入 @vh5/locales
  • 共享样式引入

不需要复制粘贴,不需要手改配置,60 秒启动新应用。


3. Turborepo 加持的构建缓存

# 交互式选择启动
pnpm dev

# 直接启动指定应用
pnpm dev:vant
pnpm dev:nutui
pnpm dev:varlet

Turborepo 会自动:

  • 缓存构建产物 — 代码没变就不重新构建,直接复用
  • 并行执行 — 共享包与应用同时编译
  • 依赖拓扑排序 — 自动处理包间依赖顺序,不用手动 --filter

增量构建从冷启动的 30s+ 降到缓存命中后的 2s 以内。


4. 内置 Nitro Mock 服务

不需要额外启动 Mock 服务,pnpm dev 时 Vite 自动拉起 Nitro Mock:

POST http://localhost:5320/api/auth/login       # 登录(返回 JWT)
POST http://localhost:5320/api/auth/logout      # 登出
GET  http://localhost:5320/api/user/info        # 用户信息
GET  http://localhost:5320/api/product/list     # 商品列表(支持分页)
GET  http://localhost:5320/api/product/detail   # 商品详情

支持 JWT 认证、请求拦截、分页查询,内置两个测试账号:

用户名 密码 角色
user 123456 普通用户
admin 123456 管理员

前端通过 Vite proxy 透明代理,开发体验和联调阶段完全一致,不改一行代码切到真实后端。


5. pnpm catalog 统一依赖版本

# pnpm-workspace.yaml
catalog:
  vue: ^3.5.32
  vite: ^8.0.8
  typescript: ^6.0.2
  vant: ^4.9.21
  # ...

所有 package.json 里只写 "vant": "catalog:",版本全部集中在 catalog 管理。三个 app 用的同一个版本,升级只改一处,彻底解决版本漂移问题。


6. 状态管理:Pinia + 持久化 + AES 加密

import { initStores } from "@vh5/stores";

// 初始化时传入命名空间,多应用同域部署不冲突
await initStores(app, { namespace: "h5-vant-1.0.0-prod" });
  • 开发环境:直接用 localStorage,方便 DevTools 调试
  • 生产环境SecureLS + AES 加密,敏感数据不裸奔
  • 命名空间隔离h5-vant-xxxh5-nutui-xxx 的 key 不会互相污染

7. 国际化:四语言 + 动态加载

内置简体中文、繁体中文(台湾/香港)、英文、日文五个语言:

packages/locales/src/langs/
├── zh-CN/    # 简体中文
├── zh-TW/    # 繁体中文(台湾)
├── en-US/    # 英文
└── ja-JP/    # 日文

语言包放在共享包里,各 app 通过 @vh5/locales 按需动态加载,不增加首屏包体积:

import { loadLocaleMessages } from "@vh5/locales";

// 切换语言时才加载对应语言包
await loadLocaleMessages("en-US");

8. 路由进度条 + 动态标题

三个 app 均集成了 NProgress 路由进度条和自动标题更新:

// router/guard.ts
import { startProgress, stopProgress } from "@vh5/utils";

router.beforeEach(() => startProgress());
router.afterEach(() => stopProgress());

动态标题在 bootstrap 里通过 VueUse 的 useTitle 绑定路由 meta,路由切换自动更新 document.title,无需每个页面单独处理。


工程化配置

统一 Lint 规则

所有 ESLint / Prettier / Stylelint / Commitlint / OXLint 配置在 internal/lint-configs/ 集中管理,各 app 只需一行继承:

# 检查 + 自动修复
pnpm lint

# 格式化
pnpm format

Git commit 使用 Conventional Commits 规范,Lefthook 自动执行 pre-commit 检查。

共享 Vite 配置

@vh5/vite-config 提供 defineConfig 工厂函数,内置以下插件:

插件 说明
@vitejs/plugin-vue Vue 3 SFC + defineModel
unplugin-auto-import API 自动导入(vue、pinia、vueuse)
unplugin-vue-components 组件按需自动注册
vite-plugin-vue-devtools Vue DevTools
postcss-px-to-viewport px → viewport 移动端适配
vite-plugin-html HTML 模板变量注入
vite-plugin-compression Gzip/Brotli 构建压缩
vite-plugin-pwa PWA 离线支持
nitro-mock 自动启动 Mock 服务
vite:license 构建产物注入版权信息

vsh CLI 工具集

pnpm create-app        # 创建新 H5 应用
vsh lint               # 代码检查
vsh check-circular     # 循环依赖检测
vsh check-dep          # 未使用依赖检查
vsh publint            # package.json 规范检查
vsh code-workspace     # 生成 VSCode workspace 文件

快速开始

# 克隆
git clone https://github.com/fonghehe/vue-h5-template.git
cd vue-h5-template

# 安装(需要 Node.js >= 20.12.0 + pnpm >= 10)
pnpm install

# 开发(交互式选择应用)
pnpm dev

# 或直接启动指定应用
pnpm dev:vant     # Vant 版,端口 5778
pnpm dev:nutui    # NutUI 版,端口 5777
pnpm dev:varlet   # Varlet 版,端口 5779

# 创建新应用
pnpm create-app

# 构建所有应用
pnpm build

适合哪些场景

  • ✅ 团队需要维护多个移动端 H5 项目
  • ✅ 想在不同 UI 框架之间灵活切换
  • ✅ 需要快速搭建标准化的新 H5 应用
  • ✅ 希望统一团队的工程化规范(Lint、TypeScript、构建)
  • ✅ 学习 Turborepo Monorepo 最佳实践

浏览器支持

支持现代浏览器和移动端浏览器,不支持 IE。

Edge Firefox Chrome Safari
≥ 80 ≥ 78 ≥ 80 ≥ 14

写在最后

这个模板目前在我自己的几个项目里实际使用,持续迭代中。

如果你觉得有帮助,欢迎 Star ⭐ 和 PR 🎉

有问题或建议欢迎提 Issue 讨论!

❌