Skip to content

移动端坑位 ​

适用端:移动端 | 类型:排错

本页是移动端专属的按症状查索引,24 条(编号 M1–M24)。每条只写「现象 → 根因 → 怎么办」,机制细节链到本页所在章的正文页。

三条约定与坑位索引一致:

  1. 每条都有实测证据——源码锚点、脚本量测结果、产物里的字面量,或本仓库自己记录的构建输出。没有证据的不进清单,只在「未证实」里出现。
  2. 标 🔴 的是会咬人的:安全暴露、发布事故、或排查方向会被带偏到别处。
  3. 正文页各自的「坑与注意」段是贴着上下文的提醒;本页是按症状找的索引,同一件事两边都出现时不重复展开。

跨端通用的坑(数据库与多租户、菜单与权限、后端构建部署、代码生成器、测试协作)在坑位索引,那里用编号 A1–F6,与本页的 M 编号是两套互不复用的空间。那页的 G 节反过来指向本页标 🔴 的那几条,好让「上线前过一遍」能在一页里做完——条目正文只在本页有一份,那边只是指路。

索引 ​

最后一列是「机制在哪页」——本页只写现象与怎么办。

#一句话严重度机制在哪页
M1flex-1 单独用在 z-paging 上会高度塌陷高页面开发范式
M2忘了 :fixed="false",列表会盖住自定义 navbar高页面开发范式
M3 🔴@query 漏 catch → 永久转圈 + 未捕获 rejection高页面开发范式 · 请求封装与登录态
M4yd-* / wd-* / z-paging 不用 import,useToast 必须 import中页面开发范式 · 工程结构
M5 🔴跳转失败一律提示「页面不存在」,会把排查带偏中服务端驱动导航
M6tabbar 页不能 navigateTo,switchTab 又不接受 query高服务端驱动导航
M74 个 tabbar 项共用同一个 route,按 route 去重会误判中服务端驱动导航 · 在线表单在移动端
M8改 pages.config.ts / tabbar/config.ts 必须重启 dev server高工程结构
M9 🔴env/.env 里的 VITE_ 值会被内联进生产包。已修致命多端构建与发布
M10sync-manifest 曾把 app 产物路径写死成 dist/dev/app。已修中多端构建与发布
M11约 52% 的 H5 产物是用户点不到的分包中移动端总览 · 多端构建与发布
M12VITE_SHOW_SOURCEMAP 与 VITE_FALLBACK_LOCALE 都是空写低多端构建与发布
M13versionName / versionCode 硬编码,App 端永远 1.0.0中多端构建与发布
M14build:h5 会弹浏览器,build:mp 会拉开发者工具中多端构建与发布
M15小程序上传的默认版本号取自 yudao-version中多端构建与发布
M1656 个 dev/build 脚本里只有 3 个挂了 init-baseFiles 前置钩子中环境准备与启动 · 多端构建与发布
M17staticUrl() 会把 VITE_STATIC_BASEURL 拼在 /static/ 前。已修高多端构建与发布
M18 🔴三个身份标识仍是上游的,上传会传到上游小程序致命多端构建与发布
M19 🔴请求加密开关是 true,但没有任何调用方传 isEncrypt中请求封装与登录态 · 多端构建与发布
M20eruda 只在 h5 + development 注入低环境准备与启动
M21src/types/* 大部分不入库,新克隆 type-check 会报找不到模块中工程结构 · 移动端总览
M22src/components/yudao-ui/ 目录名刻意不改低工程结构
M23Android 权限清单整段继承上游中多端构建与发布
M24unibest 上游合并要按月推进,不能整段 merge中移动端总览

锚点是编号,不是标题

与坑位索引同一套做法:标题后用 {#m1} 显式声明锚点,全站引用写 #m1。改标题随意,别改 {#mx};编号一旦发出就不复用、不重排。


一、布局与组件 ​

M1. z-paging 高度塌陷:flex-1 必须配 min-h-0 ​

现象:列表页只显示第一屏,往下滚不动;或者列表区域高度为 0,整页空白但 navbar 和搜索框都在。

根因:flexbox 子项的 min-height 默认是 auto,不会小于内容高度。flex-1 单独用在 z-paging 上时,容器高度由内容反推,z-paging 内部的 scroll-view 拿不到确定高度,滚动就失效了。

怎么办:父容器 h-screen flex flex-col overflow-hidden(全局类 .yd-page-container-paging,src/style/index.scss:42-43),z-paging 上写 class="min-h-0 flex-1"。这是全仓的既有约定,不是个别页面的写法:min-h-0 出现在 643 个 .vue 文件里。范本见 src/pages/bpm/components/todo-list.vue:2,10。

M2. 忘了 :fixed="false",z-paging 会盖住自定义 navbar ​

现象:自己写的 <wd-navbar> 或搜索栏被列表盖住,或者页面出现两层滚动条。

根因:z-paging 默认用 position: fixed 全屏铺满,它不知道页面上还有别的元素。

怎么办:加 :fixed="false",让它改为吃父容器高度(配合 M1)。全仓 367 个 .vue 用了 <z-paging>,:fixed="false" 出现 372 次——基本是「用了 z-paging 就一定会写」。

M3. @query 漏 catch → 永久转圈 + 未捕获 rejection ​

🔴 现象:页面一直转圈,控制台一条 Uncaught (in promise),用户看到的是「页面打不开」。

根因:移动端把「业务码非 0」从 resolve 改成了 reject(src/http/http.ts:186,注释「reject 替代原本的 resolve」)。所以后端返回错误时,await 一定抛。z-paging 的 @query 回调如果不 catch,既不会 complete()(于是一直转圈),也不会 complete(false)(于是没有错误态),rejection 还没人接。

怎么办:try 里成功走 pagingRef.value.complete(list),catch 里走 pagingRef.value.complete(false)。范本在 src/pages/message/index.vue:108-122。这一条是待修的 17 个异常页的主要形态之一——批量巡检时按「有没有 catch」筛,比按页面名筛准。

:auto="false" 是另一件事

src/pages-infra/form-design/run/index.vue 的 z-paging 写了 :auto="false"(全仓 13 处),目的是等渲染配置到位再发第一次查询,否则会在没有排序和查询条件的情况下先打一次 /page,第一页和后面几页的规则不一致。这与 M3 无关,别混着改。

M4. yd-* / wd-* / z-paging 不用 import,但 useToast 必须 import ​

现象:useToast is not defined;或者反过来,给 wd-button 补了一行 import 结果报重复声明。

根因:三条不同的解析链,覆盖范围不一样:

来源谁解析要不要 import
wd-*(wot-design-uni)、z-pagingpages.config.ts 的 easycom不要
yd-*(自研)easycom 规则 ^yd-(.*) → @/components/yudao-ui/yd-$1/yd-$1.vue不要
src/components/** 下的本地组件UniComponents(vite.config.ts:93-99)不要
src/hooks/** 下的函数AutoImport({ dirs: ['src/hooks'] })(vite.config.ts:155-160)不要
Vue / uni-app API(ref、computed、uni.*)AutoImport({ imports: ['vue', 'uni-app'] })不要
useToast来自 @wot-ui/ui/components/wd-toast,不在 src/hooks 里,也不在 src/types/auto-import.d.ts 里要

怎么办:import { useToast } from '@wot-ui/ui/components/wd-toast'(范本 src/pages/message/index.vue:80)。判断标准很简单:只有 src/hooks/ 下的东西被自动导入,第三方包里的 hook 一律手动 import。

二、路由与页面栈 ​

M5. 跳转失败一律提示「页面不存在」,会把排查带偏 ​

🔴 现象:点工作台某个菜单弹「页面不存在」,于是去查 system_nav_node 的 route 拼写、查 src/pages.json 有没有这条路由——都查不出问题,因为路由是对的。

根因:src/pages/index/index.ts:196-198(switchTab)与 :204-206(navigateTo)的 fail 回调都是同一句 toast.show('页面不存在'),把所有失败原因都归成这一种。而 uni.navigateTo 的失败原因不止「路由不存在」,最典型的另一种是页面栈已满:uni-app 的 navigateTo 层级上限是 10 层,超过就 fail。

怎么办:先确认路由真的存在——用服务端驱动导航里那段脚本把 src/pages.json 的 764 条路由 dump 出来 grep。路由在的话,就是栈满了:往回退几层再进,或者把这个入口改成 redirectTo(替换当前页,不压栈)。

想改提示语的话

把 fail 改成打印 err.errMsg 更有用(uni 会给出 navigateTo:fail page "xxx" is not found 或 navigateTo:fail webview count exceed limit 这类具体原因),但要同步改两处——switchTab 和 navigateTo 各一份。

M6. tabbar 页不能 navigateTo,switchTab 又不接受 query ​

现象:跳 tabbar 页白跳(页面不动),或者跳过去了但参数丢了。

根因:uni-app 的两条硬约束——navigateTo 不能跳 tabbar 页;switchTab 的 url 不接受 query 参数。

怎么办:先判类型再选 API,参数走 globalData 中转。既有实现在 src/pages/index/index.ts:188-208:isTabBarPage(path)(src/tabbar/config.ts:151)为真时,若 query 非空先 setTabParams(query)(src/utils/url.ts)再 uni.switchTab({ url: path });否则 uni.navigateTo({ url: menu.url })(注意这一支传的是带 query 的完整 url)。同样的分支在 navigateBackPlus(src/utils/index.ts:220-241)与 src/utils/index.ts:199-208 也各有一份。

M7. 4 个 tabbar 项共用同一个 route,按 route 去重会误判 ​

现象:巡检脚本 / 埋点 / 权限校验按 route 统计页面,发现「审批」下 4 个入口只算 1 个页面;或者按 route 建的映射表出现键冲突。

根因:本地导航树里 4 个 tabbar 项(我的流程 / 待办 / 已办 / 抄送)的 route 全是 /pages/bpm/index,靠 query 区分。在线表单也是同一套路:所有表单入口的 route 都是 /pages-infra/form-design/run/index,只有 query 里的 code 不同(后端 FormDesignServiceImpl#buildNavNodeConfig 里 APP_NAV_ROUTE 是常量)。

怎么办:任何「一个入口一个键」的场景,键要用 route + query 而不是 route。实测清单见服务端驱动导航与在线表单在移动端。

M8. 改 pages.config.ts / tabbar/config.ts 必须重启 dev server ​

现象:加了一个页面 / 改了 tabbar,浏览器里没变化,或者报「page not found」。

根因:这两个文件是生成 src/pages.json 的输入,而 pages.json 是产物(且被 gitignore,.gitignore:43)。HMR 覆盖不到它。vite.config.ts 只给 vite.config.ts 自己配了 ViteRestart(:161-164),其余配置文件改了都不会自动重启。

怎么办:Ctrl-C 后重跑 pnpm dev。改 env/*、manifest.config.ts、src/tabbar/config.ts 同理。

三、构建与产物 ​

M9. env/.env 里的 VITE_ 值会被内联进生产包 ​

🔴 现象:生产环境的登录页自动填好了用户名和密码。

根因:env/.env 是所有 mode 的公共基底,production 也加载它;而 Vite 会把 import.meta.env.VITE_* 静态内联进产物,运行期没有任何开关能摘掉。原先 VITE_APP_DEFAULT_LOGIN_{TENANT_ID,USERNAME,PASSWORD} 就写在这里,消费点是 src/pages-core/auth/login.vue:123-124(无条件填进 formData)与 components/tenant-picker.vue:50。

实测:2026-08-30 那次 H5 构建的产物里能直接搜到明文——

dist/build/h5/assets/pages-core-auth-login.Dx0p7Pwd.js
  … t=O({username:"admin",password:"admin123",captchaVerification:""}) …

怎么办:已修(提交 48bf755a)。三项默认值移到 .env.development 与 .env.test(都是开发态 mode),.env 原位留了注释说明为什么不能挪回去。用 Vite 自己的 loadEnv 逐 mode 验过:development / test 仍能取到,production 三者均为 undefined。

推广开来看:任何 VITE_ 开头的值都要当作「会出现在公开产物里」对待。自查办法见多端构建与发布——grep -rl "要查的值" dist/build/h5/assets/。

M10. sync-manifest 曾把 app 产物路径写死成 dist/dev/app ​

现象:dist/ 下多了一个空的 dev/app/ 目录——连 H5 构建也会造出来。仓库里那个 2026-08-30 造的就是。

根因:vite-plugins/sync-manifest-plugins.ts 的 writeBundle 把目标写死成 ./dist/dev/app/manifest.json,而且 mkdirSync 在「有没有 plugins 可同步」的判断之前无条件执行。第二层后果更严重:uni build -p app 的产物在 dist/build/app,插件却往 dist/dev/app 写,同步结果永远进不了生产产物。

怎么办:已修(提交 5f653c4b)。非 app 平台直接返回;build / dev 按 NODE_ENV 推导(与同目录 open-dev-tools.js:26,99 早就在用的口径一致);没有 app-plus.distribute.plugins 时在建目录之前就返回。改完用 esbuild 转出插件、逐组合调 writeBundle.handler 验过 7 例。

当前是否有实际影响:没有——manifest.config.ts 从未生成过 app-plus.distribute.plugins 字段(实测为 undefined),所以写入分支从来没执行过。要引入本地原生插件时才会用到,届时按多端构建与发布的 App 一节第 4 步配齐。

M11. 约 52% 的 H5 产物是用户点不到的分包 ​

现象:H5 产物 assets/ 13.4 MB、1242 个 js 文件,首屏加载偏重。

根因:vite.config.ts:104-121 的 UniPages({ subPackages }) 列了全部 16 个分包目录,其中 11 个(crm/erp/im/iot/mall/member/mes/mp/pay/wms/statistics)在后端没有对应模块——ainb 已把这些模块整体删除,导航树 system_nav_node 也不给它们建节点。它们编译进包,但用户永远点不到。

实测(基于 2026-08-30 的产物,见多端构建与发布):11 个不可达分包的 pages-* 分块合计 6,408 KB;另有只被 pages-statistics 引用的 yd-chart(echarts,560 KB)与只被 pages-im 引用的 livekit 分块(512 KB,已计入前者)。echarts 与 livekit-client 的 import 点全部落在这两个分包内,已逐个 grep 确认。合计约 7.0 MB / 13.4 MB ≈ 52%。

怎么办:这属于产品决策而非构建配置。目录留着是为了将来后端补上模块时能直接接回来。真要瘦身:从 subPackages 数组里去掉不要的目录,同步改 pages.config.ts 与 src/tabbar/config.ts 里的引用,路由数会从 764 降到约 190。先确认「不打算再要这些模块」。

M12. VITE_SHOW_SOURCEMAP 与 VITE_FALLBACK_LOCALE 都是空写 ​

现象:改了这两个变量,产物没有任何变化。

根因:

  • VITE_SHOW_SOURCEMAP:三个 env 文件都设了(.env.development:6、.env.test:6、.env.production:6),但全仓唯一读它的地方是 vite.config.ts:248 那行被注释掉的代码。build.sourcemap 恒定 false(:246)。
  • VITE_FALLBACK_LOCALE:manifest.config.ts:20 解构了它、:31 用它填 locale,但任何 env 文件里都没定义。实测生成出来的 src/manifest.json 里 locale 字段整个不存在(undefined 被 JSON.stringify 丢掉)。

怎么办:要 sourcemap 就改 vite.config.ts:246(注意会泄露未混淆源码,只建议对 test mode 开)。要固定语言就在 env/.env 里补 VITE_FALLBACK_LOCALE = 'zh-Hans'。或者干脆把这两处死代码删掉,别留下「看起来能配」的假象。

M13. versionName / versionCode 硬编码,App 端永远 1.0.0 ​

现象:App「关于」页显示的版本永远是 1.0.0;Android 装新版本提示「不能覆盖安装」或「版本已存在」。

根因:manifest.config.ts:28-29 写死 'versionName': '1.0.0'、'versionCode': '100',既不读 package.json:4 的 version,也没有任何脚本递增它。versionCode 不递增,Android 会拒绝覆盖安装。

怎么办:发 App 前手工把这两个值改掉,或者让它们从 package.json 读(manifest.config.ts 里已经在用 loadEnv,再 readJson('./package.json') 即可)。H5 与小程序不受影响——H5 没有版本号概念,小程序上传版本由 --version= 参数决定(见 M15)。

M14. build:h5 会弹浏览器,build:mp 会拉开发者工具 ​

现象:CI 上跑 pnpm build:h5,构建结束后多出一个浏览器进程;跑 pnpm build:mp,构建卡住或报找不到开发者工具。

根因:两个插件都会自动「弹东西」——

行为触发条件开关
visualizer 生成体积报告并 open: trueUNI_PLATFORM === 'h5' && mode === 'production'(vite.config.ts:173-180)没有环境变量开关,只能改代码或让 mode 不等于 production
自动打开微信开发者工具SKIP_OPEN_DEVTOOLS !== 'true' 且 UNI_PLATFORM 含 mp 且首次构建(vite.config.ts:194-197 → scripts/open-dev-tools.js:97-113)SKIP_OPEN_DEVTOOLS=true

怎么办:CI 上至少设 SKIP_OPEN_DEVTOOLS=true(scripts/upload-weixin.js:142-150 就是这么做的)。开发者工具 CLI 路径通过 WECHAT_DEVTOOLS_CLI_PATH 配(env/.env:9,11 有 macOS 与 Windows 两个注释掉的示例),未配置时退回 open-dev-tools.js:43(macOS)/ :53(Windows)的平台默认路径;找不到只打印提示后返回,不会让构建失败。

M15. 小程序上传的默认版本号取自 yudao-version ​

现象:微信后台看到的版本号是 2026.07.0-snapshot。

根因:scripts/upload-weixin.js:62-69 的 readPackageVersion() 取 pkg['yudao-version'] || pkg.version || '1.0.0',而 package.json:6 的 "yudao-version": "2026.07.0-snapshot" 优先于 package.json:4 的 "version": "2026.07-snapshot"。这个键名是上游遗留,本项目刻意保留(它记录的是上游合并基线,见 docs/merge/),所以不能简单删掉。

怎么办:正式发布显式传 --version=1.0.0,或设 WECHAT_UPLOAD_VERSION。回退顺序见多端构建与发布。

M16. 56 个 dev/build 脚本里只有 3 个挂了 init-baseFiles 前置钩子 ​

现象:手工删掉 src/pages.json 后直接 pnpm build:h5,报找不到页面 / 产物是空的。

根因:src/pages.json 与 src/manifest.json 都不入库(.gitignore:42-43),要先由 scripts/create-base-files.js 造桩、再由 UniPages / UniManifest 覆盖成真内容。但 npm/pnpm 的 pre<name> 钩子只对脚本名精确匹配生效:只有 predev、predev:app、predev:mp 三条,覆盖 pnpm dev / dev:app / dev:mp。dev:h5、dev:test、dev:prod、dev:mp-weixin、以及全部 25 条 build:* 都没有。

怎么办:目前不出问题,是因为 prepare(package.json:94)在 pnpm install 时已经跑过一次 init-baseFiles——兜底在安装期而不是构建期。踩空了就手工 pnpm init-baseFiles。

桩文件里的路由是不存在的

create-base-files.js 生成的 pages.json 桩只有两条路由,其中 pages/me/me 在本仓库不存在(真实的「我的」页在 pages-core 分包)。桩随后会被插件覆盖,所以当前无害;但任何在插件之前读 pages.json 的工具都会拿到一条 404 路由。

四、静态资源与外部服务 ​

M17. staticUrl() 会把 VITE_STATIC_BASEURL 拼在 /static/ 前 ​

现象:图片全部裂开,请求打到了一个陌生域名。

根因:src/utils/download.ts:335-343 的 staticUrl(path) 对非 http(s) / blob: / data: 的入参,一律返回 ${VITE_STATIC_BASEURL}${normalizedPath}。而这个变量原先指向上游演示域名 http://test.yudao.iocoder.cn,于是 /static/qrcode.png 被拼成了上游域名下的路径。

怎么办:已修(提交 e1e4be57)。env/.env:43 与 .env.production:17 都改成空串 '',让 /static/ 走应用自身。要指向 CDN 就填完整域名且不要带 /static 后缀——后缀由入参自己带。

注意:/static/ 是 uni-app 的约定目录,只有放在 src/static/ 下的文件才会被原样复制进产物。放在别处的图片即使路径写对了也不会被打包。

M18. 三个身份标识仍是上游的 ​

🔴 现象:pnpm upload:mp-weixin 会把包上传到上游的小程序账号(或者因私钥不匹配而失败);HBuilderX 云打包报 appid 不属于当前账号;地图组件不显示。

根因:env/.env 里三项还是上游演示值——

变量当前值谁在读
VITE_WX_APPID(:5)wx63c280fe3248a3e7manifest.config.ts:127 → mp-weixin.appid;scripts/upload-weixin.js:156-160(缺失时 throw)
VITE_UNI_APPID(:4)__UNI__D1E5001manifest.config.ts:26 → appid,HBuilderX 云打包按它认账号
VITE_BAIDU_MAP_KEY(:53)Y2aJXiswwPxy6mwFs1z9c7U5gwX9WfUN地图组件;明文 AK 已进仓库也会进产物

怎么办:换成自己的值。VITE_WX_APPID 不能简单删掉(上传脚本会 throw),必须替换。DCloud appid 要在 HBuilderX 里重新获取。百度地图 AK 要在百度开放平台申请,并且配置域名白名单,否则即使换对了也可能被拒。

M19. 请求加密开关是 true,但没有任何调用方传 isEncrypt ​

🔴 现象:以为接口是加密的,抓包发现全是明文 JSON——而 env/.env:75 明明白白写着 VITE_APP_API_ENCRYPT_ENABLE = true。

根因:VITE_APP_API_ENCRYPT_ENABLE 只是能力开关(src/utils/encrypt.ts:10,在 :157 与 :193 各挡一次)。真正的闸门是 src/http/interceptor.ts:83 的 if (options.isEncrypt)——逐请求开启。而全仓库 isEncrypt 只出现在三个地方:类型声明 src/http/types.ts:13、闸门 interceptor.ts:83、以及响应侧另一个变量 isEncryptResponse(src/http/http.ts:85-86)。没有任何调用方传过 isEncrypt: true。

怎么办:现状是「请求加密从不触发;响应解密只在服务端下发加密头时才走」。要真启用,得先解决一个前提问题:env/.env:78-79 的两把 AES 密钥是明文写在仓库里的,会被内联进每一端的产物(同 M9 的机制)。启用前必须换成运行期下发的方案,否则加密等于没加。

五、调试与类型 ​

M20. eruda 只在 h5 + development 注入 ​

现象:pnpm dev:test / dev:prod 打开页面,右下角没有调试面板按钮,以为是坏了。

根因:vite.config.ts:189-191 的 vitePluginEruda({ open: UNI_PLATFORM === 'h5' && mode === 'development' })。dev:test 的 mode 是 test、dev:prod 是 production,都不满足。

怎么办:要在 test/prod mode 下调试,改 vite.config.ts:190 的条件。或者直接用浏览器 devtools(H5 端本来就够),eruda 主要是给真机 H5 用的。

M21. src/types/* 大部分不入库,新克隆 type-check 会报找不到模块 ​

现象:全新克隆跑 pnpm type-check,报 Cannot find module '@/pages.json'。

根因:.gitignore:34 是 src/types/*,只有 4 个例外被显式放行(:36,38,40,41)。实测:

文件是否入库谁生成
src/types/auto-import.d.ts✓ TRACKEDAutoImport(vite.config.ts:157)
src/types/local-components.d.ts✓ TRACKEDUniComponents(vite.config.ts:98)
src/types/uni-pages.d.ts✗ not trackedUniPages(vite.config.ts:122)
src/types/env.d.ts✗ not tracked—
src/pages.json / src/manifest.json✗ not tracked(.gitignore:42-43)UniPages / UniManifest

而 src/utils/index.ts:3 直接 import { pages, subPackages } from '@/pages.json',HOME_PAGE(:185)也依赖它。

怎么办:先 pnpm install(prepare 会跑 init-baseFiles 造桩),再跑一次 pnpm dev 让插件生成真文件,然后才 pnpm type-check。这与 Web 仓的 F2(auto-*.d.ts 只由 dev server 生成)是同一类问题,但移动端更严重:Web 仓的 auto-*.d.ts 只是类型缺失,移动端是 pages.json 这个运行时也要用的模块根本不存在。

新增组件后要提交 local-components.d.ts

src/types/local-components.d.ts 是入库的,所以在 src/components/ 下新增组件后,要跑一次 dev 让它重新生成,并把这个文件一起提交,否则别人 type-check 会报找不到组件。反过来,uni-pages.d.ts 不入库,别去提交它。

六、工程协作 ​

M22. src/components/yudao-ui/ 目录名刻意不改 ​

现象:看着像上游残留,想「顺手改成 enlev-ui」。

根因:这个目录被两处双重引用——easycom 规则 ^yd-(.*) → @/components/yudao-ui/yd-$1/yd-$1.vue(pages.config.ts),以及自动生成的组件类型声明。改名牵连 56 个文件的 import,且没有任何收益。

怎么办:不改。目录名不代表归属变更;归属口径写在 LICENSE、licenses/ 与 THIRD-PARTY-NOTICES.md 里。同理,仓库内的 docs/ 是 unibest 原版站点(含上游打赏/赞助页),属遗留但不要顺手删(不可逆,且 docs/merge/ 的合并记录在同一目录下)。

M23. Android 权限清单整段继承上游 ​

现象:App 上架被应用商店拒审,理由是「申请了与功能无关的权限」。

根因:manifest.config.ts:66-82 的 15 条权限整段来自上游,含 READ_LOGS、WRITE_SETTINGS、READ_PHONE_STATE、GET_ACCOUNTS、MOUNT_UNMOUNT_FILESYSTEMS 这类宽权限,而本项目的 App 端功能面并没有用到它们。

怎么办:当前 App 端未打包发布,所以还没有实际后果。真要上架前必须逐条核对,只保留有对应功能的权限。同一段里还有 minSdkVersion: 21 / targetSdkVersion: 30(:63-64)——targetSdk 30 低于主流商店当前要求,也要一并抬。

M24. unibest 上游合并要按月推进,不能整段 merge ​

现象:想跟上 unibest 上游,git merge unibest/main 后冲突面铺满整个工程。

根因:本仓库是 unibest 4.1.0 骨架 + 芋道移动端业务页的混合体,且已经整体改名。上游的工程配置(vite.config.ts、pages.config.ts、src/tabbar/、src/router/interceptor.ts)与本项目定制高度重叠,整段 merge 会把定制冲掉。

怎么办:照仓库自己的 docs/merge/README.md 走——按月份推进,每个月内部再按「完全合并 / 部分合并 / 忽略」分类处理,不整段 merge 也不整段 cherry-pick。月度记录在 docs/merge/2025-12.md 到 2026-05.md(6 个月,共 1037 行)。已明确的口径:先做低风险小改(微信小程序 baseUrl、devtools CLI path、tabBar fallback、import-sort、native plugin copy 日志);tabbar 同步修复单独做专项,它不是低风险项;CLI、demo、模板文档、changesets、版本号类改动默认忽略。

未证实 ​

  • 10 层页面栈上限(M5)本机未实测触发:uni-app 官方文档写明 navigateTo 的层级上限是 10,fail 回调会拿到 webview count exceed limit 之类的 errMsg。本仓库源码里没有任何针对该上限的处理或注释,也没有复现过——M5 的已证实部分是「所有 fail 都提示同一句『页面不存在』」(源码锚点确凿),栈满是其中一种会被误报的原因。
  • M11 的体积数字基于 2026-08-30 的过期产物:仓库里的 dist/ 比 HEAD 早两个月,<title> 还是改名前的旧品牌。比例(约 52%)应当稳定,绝对值会变。
  • M23 的商店拒审是行业常识推断,本项目没有真的提交过 App 审核。
  • docs/merge/ 记录的上游合并结论未复核:那 6 个月度文档是上一轮工作的产出,本轮只引用、没有重新对上游做一次 diff。

相关页面 ​