uniapp-vue3 架构与工程化解决方案总结
本项目基于 Vite + Vue 3 + UniApp 构建,针对 SaaS 模式下的 单仓库多租户(Multi-Tenant) 场景进行了深度定制。通过自定义构建脚本与运行时架构,解决了小程序开发中常见的多应用维护、动态资源丢失、多语言,多主题切换等核心痛点。
1. 核心架构:单仓库多应用 (Monorepo-like)
痛点分析
在 SaaS 业务中,需要为几十甚至上百个客户(租户)打包独立的小程序。传统做法通常涉及:
- 代码冗余:为每个客户维护独立分支或仓库,核心业务逻辑同步困难(O(N) 维护成本)。
- 配置混乱:发版时需手动修改
appid、接口地址等,极易出现人为失误(如发错版、环境混淆)。
解决方案
采用 配置驱动构建 的架构模式:
- 差异化配置管理:所有客户的差异化信息(AppID、接口环境、特有页面)独立存储在 scripts/setting/ 目录下。
- 构建时动态注入:
- Manifest 重写:构建脚本 scripts/build/index.js 会在编译前读取指定客户配置,自动覆写
manifest.json中的appid。 - Pages 动态合并:基于 scripts/build/baseConfig.ts 定义公共页面,构建时动态合并客户特有的
subPackages,实现“按需打包”,有效控制包体积。
- Manifest 重写:构建脚本 scripts/build/index.js 会在编译前读取指定客户配置,自动覆写
2. 动态资源构建:强制扫描与入口注入
痛点分析
Vite/Rollup 的 Tree Shaking 机制极其严格。对于未被显式引用的文件(例如:按需加载的国际化 JSON、通过后端下发路径加载的动态组件),打包时会被直接丢弃,导致运行时报错。
解决方案
在 vite.config.ts 中实现自定义扫描逻辑:
- Glob 扫描:使用
fast-glob扫描src/**/i18n/index.ts(国际化文件)和src/asyncUtils/**/*.{js,ts,vue}(异步工具库)。 - 强制入口注入:通过
rollupOptions.input将扫描到的文件显式添加到构建入口中。// vite.config.ts 示例逻辑 const extraFiles = glob.sync(['src/**/i18n/index.ts', 'src/asyncUtils/**/*.{js,ts,vue}']); // ...将其加入 rollupOptions.input - 效果:确保了所有动态资源在构建产物中永久存在,彻底解决了“本地运行正常,打包后文件丢失”的顽疾。
3. 国际化:分包异步加载 (Lazy-Load i18n)
痛点分析
随着业务增长,主包的语言包文件(zh.json/en.json)体积越来越大,影响小程序启动速度。且不同分包的翻译内容耦合在一起,维护困难。
解决方案
- 分包策略:将翻译文件分散在各个分包中(如
src/subPackageScanQrOrder/i18n/index.ts)。 - 运行时自动加载:
- 在 src/store/i18/index.ts 中建立分包映射表
i18nMap。 - 利用路由拦截或页面生命周期,调用
mergeLocalMessageByRouter(hashPath),根据当前访问的路径按需加载对应的语言包。
- 在 src/store/i18/index.ts 中建立分包映射表
- 效果:显著减小主包体积,实现“访问哪个业务模块,加载哪份语言包”。
4. UI 工程化:自动主题切换
痛点分析
不同租户或不同业务模块(如“电商主页”需蓝色商务风,“扫码点餐”需红色营销风)对 UI 风格有不同要求。
解决方案
基于 CSS 变量 + 路由监听 的动态主题系统:
- 主题定义:在 src/store/useStyle/theme/ 下定义多套主题配置(
light,dark,red),包含颜色变量与 CSS 变量。 - 配置规则:在 src/utils/env.ts 中配置主题映射规则(例如:
subPackageScanQrOrder模块强制使用red主题)。 - 自动切换:
- 应用启动时(App.ku.vue),监听路由参数
hashPath。 - 调用
useStyles().switchThemeByRouter()自动匹配并应用相应主题。
- 应用启动时(App.ku.vue),监听路由参数
- 效果:用户在不同业务模块间跳转时,系统自动完成主题色、圆角、间距的无缝切换。
5. 开发体验:环境变量与可视化工具
痛点分析
- 代码中硬编码(Hardcode)导致环境切换困难。
- 几十个配置 ID 难以记忆,命令行操作繁琐。
解决方案
- 全链路环境变量:
- 构建脚本通过 scripts/choreJS/defineEnv.js 将配置注入
process.env。 - 前端代码统一通过
process.env.SITE_CHANNEL_TYPE等变量访问,代码中无任何敏感信息。
- 构建脚本通过 scripts/choreJS/defineEnv.js 将配置注入
- 可视化构建服务:
- 提供 scripts/server.js 本地服务(默认端口 3003)。
- 开发者可通过 Web 界面直接点击选择配置并触发构建,无需记忆复杂的 CLI 命令。
6. 全局交互:统一弹窗
痛点分析
传统弹窗组件需要在每个页面单独引入,代码冗余且无法在 Store/纯 JS 文件中调用。
解决方案
- 全局单例:在根组件 App.ku.vue 中挂载
<HjModal />。 - Store 驱动:通过 Pinia Store (src/store/hjModal/index.ts) 管理弹窗状态。
- 命令式调用:支持在任何地方通过
useModalStore().confirm(...)唤起弹窗。 - 能力增强:不仅支持基础 Alert/Confirm,还封装了支持翻页、富文本展示的“公告模式”,适应复杂的通知场景。