uniapp-template:基于 uni-app + Vue 3 + Vite 的多端业务项目模板实践

2 阅读8分钟

前言

很多 uni-app 项目一开始都很快:建页面、调接口、跑 H5、发小程序,好像没有什么难度。

但当项目进入真实业务阶段,问题会迅速变多:登录态怎么持久化?不同角色如何控制页面权限?小程序主包体积如何控制?H5 扫码和微信小程序能力如何共存?UI 组件库、暗黑模式、Tailwind、多端样式又该怎么统一?

这个项目就是围绕这些真实问题整理出来的一个 uni-app-template:它不是空白脚手架,而是一个基于 uni-app + Vue 3 + Vite 的多端业务启动模板,内置了登录、权限、角色化 TabBar、Wot UI、Tailwind CSS、Mock、扫码、二维码、图表分包、微信小程序上传等常见能力。

项目地址:

https://github.com/jiayc4215/uniapp-template

技术栈

当前模板主要使用:

  • uni-app 3:负责多端应用框架能力
  • Vue 3:组合式 API 开发业务页面
  • Vite 5:提供开发和构建能力
  • Pinia:管理登录态、用户信息、主题和 TabBar 状态
  • Wot Design Uni:提供跨端 UI 组件
  • Tailwind CSS 4 + weapp-tailwindcss:统一 H5 和小程序端原子类写法
  • @uni-helper/unh:封装开发、构建与配置生成流程
  • @uni-helper/vite-plugin-uni-pages:通过页面文件和 definePage 生成页面配置
  • @uni-helper/vite-plugin-uni-manifest:以 manifest.config.js 管理应用配置
  • better-mock:开发环境 Mock 登录与用户信息接口
  • uni-echarts + echarts:提供图表能力
  • jsQR:支持 H5 摄像头扫码解析二维码
  • uni-mini-ci:支持微信小程序 CLI 上传

为什么不是一个空白模板

空白模板的优点是干净,但真实项目往往需要重复搭建很多基础设施。

这个模板更偏向“业务启动模板 + 多端能力示例”,已经提前处理了几个常见工程问题:

  • 页面权限:页面通过 definePage({ rules: [...] }) 声明允许访问的角色
  • 路由守卫:在跳转前统一校验登录态、白名单和角色权限
  • 角色菜单:自定义 TabBar 根据当前角色动态展示
  • 持久化状态:登录态和用户信息由 Pinia 统一维护
  • 多端样式:Wot UI 与 Tailwind CSS 共同支撑业务页面
  • 暗黑模式:结合 uni-app 主题变量、Wot UI ConfigProvider 和语义色
  • 分包优化:图表、扫码、二维码等能力放入分包,降低主包压力
  • 小程序上传:内置微信小程序构建和上传脚本,方便接入发布流程

项目结构设计

源码主要放在 src 目录:

src/
├── api/                     # 接口定义
├── components/              # 公共业务组件
├── composables/             # 组合式函数
├── echarts-modules/         # 图表分包
├── mock/                    # 本地 Mock
├── pages/                   # 主包页面
├── public-modules/          # 公共能力分包,例如扫码、二维码
├── router/                  # 路由拦截与权限控制
├── store/                   # Pinia 状态管理
├── tabbar/                  # 自定义 TabBar
├── utils/                   # 请求、路由、环境等工具
├── App.vue
└── main.js

根目录里保留了几个关键配置文件:

manifest.config.js       # uni-app manifest 配置源文件
pages.config.js          # pages.json 配置源文件
unh.config.js            # @uni-helper/unh 配置
vite.config.js           # Vite 与 uni-app 插件配置

pages.jsonmanifest.json 不再手写维护,而是由 @uni-helper/unh 根据源配置、页面内 definePagemanifest.config.js 自动生成。这样做的好处是配置入口更集中,页面规则也更靠近页面本身。

登录、权限与角色化 TabBar

模板内置了两个角色:

  • admin
  • user

页面可以通过 definePage 声明访问规则:

<script setup>
definePage({
  style: {
    navigationBarTitleText: "管理台"
  },
  rules: ["admin"]
})
</script>

路由权限主要由三部分组成:

  • 页面内 definePage 声明页面规则
  • src/router/permission.js 在路由跳转前校验登录态和角色
  • src/tabbar/config.js 根据角色生成自定义 TabBar

这套设计让权限配置比较直观:新增一个页面时,可以直接在页面文件里写清楚它属于哪个角色;新增一个角色时,也能沿着登录接口、页面规则、TabBar 配置这条链路逐项检查。

权限跳转规则也比较完整:

  • 已登录访问登录页时,自动跳转首页
  • 未登录访问非白名单页面时,跳转登录页并携带 redirect
  • 已登录访问带 rules 的页面时,校验用户角色
  • 权限不足时,跳转到错误页

UI 与样式:Wot UI + Tailwind CSS

项目集成了 Wot Design Uni,并通过 pages.config.jseasycom 自动解析 wd-* 组件。业务页面可以直接使用 Wot UI 组件,不需要在每个页面里重复导入。

同时,模板也接入了 Tailwind CSS 4 + weapp-tailwindcss,用于统一 H5 和小程序端的原子类写法。安装依赖后会执行:

weapp-tw patch

这一步用于适配小程序端 Tailwind 转换。

在暗黑模式上,项目没有简单堆 dark: 类,而是采用了更工程化的三层方案:

  • manifest.config.js 开启 H5 和微信小程序的 darkmode
  • src/theme.json 提供 uni-app 平台主题变量
  • wd-config-provider 接管 Wot UI 组件主题,并通过 Tailwind 语义色服务业务页面

例如业务页面优先使用语义类:

<view class="bg-fill-bottom text-text-main">
  <view class="border border-line-main bg-fill-oppo">
    <text class="text-text-secondary">内容</text>
  </view>
</view>

这样页面不需要硬编码两套颜色,也更容易保持 H5 和小程序端视觉一致。

分包实践:把重能力放到该去的地方

小程序项目绕不开包体积问题。模板中把图表和公共能力拆到了分包:

src/echarts-modules     # 图表分包
src/public-modules      # 扫码、二维码等公共能力分包

图表能力使用 uni-echarts + echarts,并推荐从 echarts/core 按需注册图表、组件和渲染器:

import { PieChart } from "echarts/charts"
import { DatasetComponent, LegendComponent, TooltipComponent } from "echarts/components"
import * as echarts from "echarts/core"
import { CanvasRenderer } from "echarts/renderers"

echarts.use([LegendComponent, TooltipComponent, DatasetComponent, PieChart, CanvasRenderer])

同时,微信小程序端开启了分包优化:

export default defineManifestConfig({
  "mp-weixin": {
    optimization: {
      subPackages: true
    }
  }
})

并配合 @uni-ku/bundle-optimizer 控制跨包引用和构建表现。对于业务项目来说,这种拆分方式比后期再被动治理主包体积更稳。

H5 扫码与二维码能力

模板里还放了一个实践项目:即客二维码解码。它是一个二维码处理工具示例,支持二维码解析和生成。

其中 H5 扫码基于:

  • navigator.mediaDevices.getUserMedia
  • canvas
  • jsQR

摄像头画面会绘制到 canvas,再交给 jsQR 解析二维码内容。扫码组件识别成功后触发 success 事件,扫码页通过 uni.$emit("scanResult", data) 抛出结果。

需要注意的是,H5 摄像头能力对运行环境有要求:

  • 页面需要运行在 HTTPS 环境
  • iOS 浏览器以 Safari 内核权限表现为准
  • 部分旧安卓浏览器可能不支持 getUserMedia
  • 离开页面时要释放 MediaStreamTrack

项目文档里也对常见错误做了整理,比如 NotAllowedErrorNotFoundErrorNotReadableErrorSecurityError 等,方便排查摄像头授权问题。

Mock 与请求封装

开发环境下,如果设置:

VITE_APP_MOCK=true

src/main.js 会动态导入 src/mock,启用本地 Mock。

当前 Mock 主要覆盖:

  • 登录接口
  • 用户信息接口
  • 不同角色返回不同 token 和用户信息

这对模板项目很有用。即使后端接口还没准备好,也可以先把登录、角色权限、TabBar 切换、页面跳转这些核心链路跑通。

微信小程序构建与上传

项目提供了微信小程序上传脚本:

pnpm upload:mp

也支持指定版本号、描述和机器人编号:

pnpm upload:mp --version=1.0.1
pnpm upload:mp --desc="修复登录问题"
pnpm upload:mp --version=1.0.1 --desc="版本说明" --robot=2

上传流程大致是:

  1. 构建微信小程序产物
  2. 读取生产环境变量中的 VITE_WX_APPID
  3. 查找上传私钥
  4. 临时生成 .minicirc
  5. 执行 minici --platform weixin
  6. 上传结束后删除临时配置

私钥文件不会提交到仓库,上传前需要在微信公众平台开通“小程序代码上传”能力,并配置上传 IP 白名单。

快速开始

环境要求:

Node.js >= 20.19.0
pnpm

安装依赖:

pnpm install

启动 H5:

pnpm dev:h5

启动微信小程序:

pnpm dev:mp-weixin

生产构建:

pnpm build:h5
pnpm build:mp-weixin

代码检查:

pnpm lint
pnpm lint:fix
pnpm lint:prettier

文档站点位于 docs/ 目录,是一个独立的 VitePress 项目:

cd docs
pnpm install
pnpm docs:dev

适合哪些场景

这个模板适合:

  • 快速启动 H5 或微信小程序业务项目
  • 需要登录、权限、角色菜单的中后台或业务应用
  • 希望统一 Wot UI、Tailwind CSS、多端样式的团队
  • 需要扫码、二维码、图表、暗黑模式等常见能力示例的项目
  • 想参考 uni-app 多端工程化配置的开发者

它不追求把所有业务都封装进去,而是把多数项目都会踩到的基础设施提前搭好。这样新项目开始时,不需要从登录、权限、分包、主题、构建发布这些问题上重新造轮子。

总结

uniapp-template 的核心价值,不是“能跑一个页面”,而是把一个 uni-app 多端项目从工程化、权限体系、UI 规范、分包策略、Mock 调试到小程序上传链路都串了起来。

如果你正在做 uni-app、Vue 3、小程序、H5 多端项目,这个模板可以作为启动项目,也可以作为工程配置参考。尤其是当项目需要角色权限、动态 TabBar、暗黑模式、扫码、图表分包和微信小程序上传时,它能省掉很多重复搭建成本。

文档地址:

https://jiayc4215.github.io/uniapp-template/