@bitz/app-mobile(apps/app-mobile)是移动端壳。它是独立栈——不导入 @bitz/platform-sdk 或 @bitz/widgets;其依赖是 Taro 4、React 18、Jotai、Capacitor 8。一份 Taro 代码被编译到三个 Web 目标——H5、微信小程序(weapp)、HarmonyOS Next hybrid(harmony-hybrid)——其 H5 产物再被 Capacitor 8 套成 Android 与 iOS 原生应用。
1. 为什么是独立、版本锁定的栈
Taro 4 当前适配 React 18 与自己的基于 Vite 的构建 runner。为保持兼容,移动端 workspace 用 resolutions 锁定:
| 关注点 | Web 应用(@bitz/app) | 移动端(@bitz/app-mobile) |
|---|---|---|
| React | 19 | 18.3.1(锁定) |
| 打包器 | Vite 8 + rolldown | Taro 的 Vite 4 runner(锁定) |
| Babel | @babel/core 8 | @babel/core 7.28(锁定) |
| 状态 | Jotai + TanStack Query | 仅 Jotai |
| 后端桥 | @bitz/platform-sdk | 无 |
这就是为什么总览页把”React 19 / Vite 8”声明限定在 Web 应用。移动端 workspace 在 Taro 跟上之前无法追随这些版本。
2. 各目标及其产出方式
| 目标 | 构建命令 | 产出 |
|---|---|---|
| H5 | yarn build:h5(taro build --type h5) | 浏览器 bundle,在 dist/——也是 Capacitor 的 web 资产 |
| 微信小程序 | yarn build:weapp(taro build --type weapp) | 微信小程序工程(miniprogramRoot: dist) |
| HarmonyOS Next hybrid | yarn build:harmony(taro build --type harmony-hybrid) | Harmony hybrid 资产,之后 sync 进原生工程 |
| Android | yarn build:android | H5 构建 + cap sync android 进原生 Android 工程 |
| iOS | yarn build:ios | H5 构建 + cap sync ios 进原生 iOS 工程 |
每个 Taro 构建都用 NODE_OPTIONS=--max-old-space-size=8092 抬高 Node 堆;脚本里已替你设好。
3. 先 web 资产、再原生的模式
Capacitor 不编译到原生;它套一个已有的 web bundle。所以原生 Android 与 iOS 应用分两步产出,webDir 耦合是承重的:
- 构建 Capacitor 壳要托管的 web 资产 → 即 H5 产物(
taro build --type h5写到dist/)。 cap sync把这些 web 资产拷进原生工程并更新插件。
# Android:先构建 web 资产,再 sync 进原生工程yarn build:android # = yarn build:android:web && yarn cap:sync:android
# iOS:同样的两步yarn build:ios # = yarn build:ios:web && yarn cap:sync:ios因为 capacitor.config.ts 设了 webDir: 'dist',H5 构建必须输出到 dist/——Capacitor 从那里读。
4. Capacitor 配置
| 字段 | 值 |
|---|---|
appId | com.bitz.editor.mobile |
appName | Bitz Editor Mobile |
webDir | dist |
bundledWebRuntime | false |
android.path | android |
ios.path | ios |
5. 首次生成原生工程
原生 android/ 与 ios/ 目录只生成一次,之后只 sync:
yarn workspace @bitz/app-mobile cap:add:android # 生成 apps/app-mobile/androidyarn workspace @bitz/app-mobile cap:add:ios # 生成 apps/app-mobile/ios之后日常工作是 build:android / build:ios(web + sync)。要配置签名、权限与商店产物,用 Android Studio 或 Xcode 打开原生工程:
yarn workspace @bitz/app-mobile cap:open:android # Android Studioyarn workspace @bitz/app-mobile cap:open:ios # Xcode# 或从根目录:yarn mobile:android:open / yarn mobile:ios:open6. HarmonyOS Next hybrid
Harmony 用 Taro 官方 @tarojs/plugin-platform-harmony-hybrid 插件(仅当 TARO_ENV === 'harmony-hybrid' 时加载)。构建产出 hybrid 资产;一个专用脚本再把它们 sync 进 Harmony 工程:
# dev watchyarn dev:mobile:harmony # taro build --type harmony-hybrid --watch
# 构建资产,再 sync 进原生 Harmony 工程yarn build:mobile:harmony # = build:harmonyyarn workspace @bitz/app-mobile harmony:sync # node ./scripts/harmony-sync.mjsharmony-sync.mjs 把 apps/app-mobile/dist → apps/app-mobile/harmony/container/entry/src/main/resources/rawfile/dist(先校验 dist、harmony/container、rawfile 目录存在;它先 rm -rf 目标再 cp -r 源)。合并便利脚本是 build:harmony:app(build:harmony && harmony:sync)。
7. 微信小程序
project.config.json 配置微信小程序工程:projectname: 'bitzeditor-mobile'、compileType: 'miniprogram'、miniprogramRoot: 'dist'、关 url-check,appid: 'touristappid'——即游客/测试模式,不是已注册的 AppID。发布前需设真实 AppID(经微信开发者工具或编辑 project.config.json)。build:weapp 把小程序产出到 dist/。
8. dev watch 命令
| 命令 | watch |
|---|---|
yarn dev:mobile(dev:h5) | H5 |
yarn dev:mobile:weapp | 微信小程序 |
yarn dev:mobile:harmony | HarmonyOS Next hybrid |
9. Taro 构建配置
config/index.ts(defineConfig):framework: 'react'、compiler: 'vite'(关 prebundle)、designWidth: 375,deviceRatio {375:2, 750:1, 828:1.81}、alias { '@': src }。H5 publicPath 在 harmony+production 下为 './' 否则 '/';h5.router.mode: 'hash'。config/dev.ts 开 source map;config/prod.ts 开 mini.optimizeMainPackage。config/taro-vite-plugin.ts 把 react/react-dom 去重到 workspace 的 React 18,把 @swc/* 与 fsevents 排出 optimizeDeps,dev server 跑在 10085(harmony)/ 10086(其他)。
10. 工具链说明
- Yarn 4.17.0 在单仓根固定(
packageManager);移动端 workspace 参与同一份 workspaces 安装。 installConfig.hoistingLimits: 'workspaces'防止 Taro runtime 被提升出移动端 workspace——否则@tarojs/runtime可能解析到错误副本,破坏多端构建。apps/app-mobile被排除在根tsconfig.json的 project references 之外(它有自己的 tsconfig 与 Taro 工具链);只有apps/app与各 package 被引用。- 干净重建:
yarn workspace @bitz/app-mobile clean清掉dist与 Vite 缓存。
11. 审一次移动端改动
- 确认你改的目标就是你构建的目标(H5 vs
weappvsharmony-hybridvs Capacitor Android/iOS)。 - 若改了 Capacitor 消费的 web 资产,确认你跑的是
build:android/build:ios(web + sync),而不是只build:h5。 - 若新增 Capacitor 插件,确认已安装并对两个平台都跑了
cap sync;需要配置时也加进capacitor.config.ts。 - 若改了 Harmony 产物,确认跑了
harmony:sync,让原生工程拿到新资产。 - 提交前跑
yarn workspace @bitz/app-mobile lint && typecheck。
12. 源核对
# 确认独立栈——移动端依赖只有 Taro + Jotai + Capacitor。rg -n '"@tarojs/|"@capacitor/|"jotai"' frontend/apps/app-mobile/package.json# 确认移动端不依赖共享 SDK/widgets。rg -n '@bitz/platform-sdk|@bitz/widgets' frontend/apps/app-mobile/package.json# 预期:第二条命令无匹配。
# 确认 Capacitor 配置与 harmony sync 目标。cat frontend/apps/app-mobile/capacitor.config.tssed -n '1,60p' frontend/apps/app-mobile/scripts/harmony-sync.mjs