解决 packages field missing or empty,并声明 onlyBuiltDependencies 以便 esbuild 等依赖可执行安装脚本。 Co-authored-by: Cursor <cursoragent@cursor.com>
tuanwei-uniapp
团员管理系统移动端(uni-app + Vue 3)。本仓库是标准 uni-app Vite CLI 工程:命令行即可构建,不需要 HBuilderX。
环境要求
| 依赖 | 实测版本 | 说明 |
|---|---|---|
| Node.js | v22.23.3 | 构建用 |
| pnpm | v12.11.2 | 唯一包管理器,不要用 npm / yarn |
| 微信开发者工具 | — | 只用来预览产物,不参与构建 |
npm 源使用官方 registry.npmjs.org。
快速开始
三条命令都在仓库根目录执行:
# 1. 安装依赖
pnpm install
# 2. 日常开发:watch 构建,不退出;产物持续写入 dist/dev/mp-weixin
pnpm dev:mp-weixin
# 3. 发布构建:一次性产出静态快照到 dist/build/mp-weixin
pnpm build:mp-weixin
package.json 里六条 scripts:dev:h5 / build:h5 / dev:mp-weixin / build:mp-weixin,
外加两条 WSL 专用变体 dev:mp-weixin:win / build:mp-weixin:win(见「在 WSL 里开发」一节)。
mp-weixin 是本仓库唯一承诺的平台;h5 两条只是顺带保留,不作保证。
产物路径与微信开发者工具的导入目录
| 命令 | 产物目录 | 什么时候用 |
|---|---|---|
pnpm dev:mp-weixin |
dist/dev/mp-weixin |
日常开发:改源码自动重编译 |
pnpm build:mp-weixin |
dist/build/mp-weixin |
发布 / 上传前:一次性静态构建 |
产物路径由 uni CLI 固定为 dist/<dev|build>/<平台>,dist/ 已在 .gitignore 中,不会进版本库。
微信开发者工具 → 「导入项目」→ 目录选 dist/dev/mp-weixin(开发)或 dist/build/mp-weixin(发布构建)。
- 要导入的是产物目录本身,也就是
app.json、project.config.json所在的那一层; 不要再往外选到仓库根目录,也不要再往里选一层。 - appid 不用手填:
project.config.json由编译器生成,appid 取自src/manifest.json的mp-weixin.appid(wxf7ee9cd5801bf7a6),项目名取自manifest.json的name。 - 开发时先起
pnpm dev:mp-weixin(它进入 watch、不退出),再导入dist/dev/mp-weixin。 - 上面两个目录是在 WSL 之外的机器上编译时的位置。在 WSL 里开发请走下一节,产物不落在
dist/。
在 WSL 里开发:开发者工具跑在 Windows 侧
微信开发者工具只有 Windows / macOS 版,没有 Linux 版,装不进 WSL。 (这台机器的 WSLg 是好的,Linux GUI 程序能显示;但开发者工具本身没有 Linux 构建,用不上。) 所以分工是「WSL 编译、Windows 运行工具」,两边靠一个落在 Windows 盘上的产物目录对接:
# WSL 侧:产物直接写到 Windows 的 D 盘,watch 常驻不退出
pnpm dev:mp-weixin:win
然后在 Windows 侧打开微信开发者工具 → 「导入项目」→ 目录选 D:\tuanwei-dev\dev\mp-weixin。
| 命令 | 产物目录(WSL 视角) | Windows 视角 | 什么时候用 |
|---|---|---|---|
pnpm dev:mp-weixin:win |
/mnt/d/tuanwei-dev/dev/mp-weixin |
D:\tuanwei-dev\dev\mp-weixin |
日常开发:watch |
pnpm build:mp-weixin:win |
/mnt/d/tuanwei-dev/build/mp-weixin |
D:\tuanwei-dev\build\mp-weixin |
发布 / 上传前:一次性构建 |
<dev|build>/mp-weixin 这一层与仓库内的 dist/<dev|build>/mp-weixin 刻意同形,
只是根从仓库内挪到了 Windows 盘上。换盘符或换目录就设 WIN_OUT_DIR:
WIN_OUT_DIR=/mnt/e/tuanwei-dev pnpm dev:mp-weixin:win
WIN_OUT_DIR 指向的目录不存在也可以:编译器会连多级父目录一起建(实测 /mnt/d/__probe/deep/nested 一次跑通,无需先 mkdir)。
为什么不把产物留在 dist/、直接让工具导入 \\wsl.localhost\...? 那条路本仓库没实测,
原理上要走 9p 网络路径;本方案不依赖它 —— 产物落在本地 NTFS,工具看到的就是一个普通 Windows 目录。
实测到的事实(WSL2 + Debian 13,2026-10-15):
dev:mp-weixin:win起 watch 后把首次全量产物写进了/mnt/d/tuanwei-dev/dev/mp-weixin;- 改一次
src/main.js,产物app.js约 3 秒后重编译落盘(1364 → 1397 字节,标记命中 1 次)。 依据是@dcloudio/vite-plugin-uni的configResolved/env.js只在未设置时才兜底默认目录, 所以UNI_OUTPUT_DIR是它认的出口,dev 与 build 两条路径都生效。 - 未实测:开发者工具那侧收到新产物后是否自动刷新界面 —— 这要工具跑起来才验得了,WSL 里验不了。 若没自动刷新,点一下工具里的「编译」即可。
目录结构
.
├── index.html # H5 入口(仅 h5 构建使用)
├── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml # pnpm 12 的 allowBuilds 白名单,见「常见问题」
├── shims-uni.d.ts
├── vite.config.js
├── src/ # uni-app 源码根(官方 src/ 布局)
│ ├── App.vue main.js manifest.json pages.json uni.scss
│ ├── pages/ packageMine/ components/ utils/ static/ uni_modules/
│ └── uni.promisify.adaptor.js
└── dist/ # 构建产物(git 忽略)
@/ 别名指向 src/。不要把源码挪回仓库根目录:vite.config.js 的 root / build.outDir
是 uni-app 官方明确不支持的,UNI_INPUT_DIR 是文档不背书的源码后门 —— 官方 src/ 布局是唯一受支持的形状。
为什么不再需要 HBuilderX
改造前这是 HBuilderX 可视化工程:构建只能在 IDE 里点菜单完成,命令行里没有等价入口,
无法在 CI、脚本或别人机器上复现构建结果。现在整个构建流程就是 pnpm install + pnpm build:mp-weixin,
退出码 0、产物在 dist/build/mp-weixin,任何人在命令行都能复现。
改造的背景、布局 / 版本 / 包管理器的取舍、以及「绝不用 @dcloudio 的 latest tag」这条硬约束,
记录在工作区仓库(本仓库之外)的 docs/adr/0009-uniapp-built-by-cli-not-hbuilderx.md。
.gitignore 里保留的 .hbuilderx/ 与 unpackage/ 只是为了不让旧的 IDE 配置与旧产物被误提交,
它们不是构建路径,与现在的构建无关。
版本口径(硬约束)
- 五个编译器包(
@dcloudio/uni-app/uni-components/uni-h5/uni-mp-weixin/vite-plugin-uni) 必须同一版本,按精确版本号 pin。具体值以package.json为准。 @dcloudio/types不受上面这条约束:它是 IDE 用的类型定义,单独窄化到3.4.31(@dcloudio/uni-app的 strict peer,不影响构建)。- 绝不用
@dcloudio包的latesttag。latest指向 Vue 2 线 (实测npm view @dcloudio/uni-app dist-tags→latest: 2.0.2-5020620260917001), 与 Vue 3 线同日期后缀、极易看错;Vue 3 线在精确版本号上(vue3tag 只给 alpha)。 vite钉精确5.2.8:@dcloudio/vite-plugin-uni的 peer 要求精确版本,不要写^。- 升级编译器走官方
npx @dcloudio/uvm(一次改全套),不要手改单个@dcloudio/*版本。
常见问题
pnpm install 报 ERR_PNPM_IGNORED_BUILDS、退出码非 0
pnpm 12 下依赖的构建脚本默认不执行,且 strictDepBuilds 默认为 true,
会把「被跳过的依赖构建脚本」判成安装失败。本项目已在 pnpm-workspace.yaml 里用 allowBuilds
显式复核(esbuild / @parcel/watcher / core-js / core-js-pure),之后
pnpm install --frozen-lockfile 退出码 0(node_modules/.modules.yaml 里记着 allowBuilds、pendingBuilds 为空)。
这里只写实测到的事实(pnpm v12.11.2):生效的键是 pnpm-workspace.yaml 的 allowBuilds;
把 onlyBuiltDependencies 写进 package.json 的 pnpm 字段,pnpm 12 会明确打印
The "pnpm" field in package.json is no longer read by pnpm(并列出被忽略的键名),无效;
写在 pnpm-workspace.yaml 里同样不生效(既不告警、也不执行那批构建脚本)。
这个键究竟从哪个版本起失效,本仓库没有逐版本复现,不下版本学结论。
构建输出一堆 sass @import / legacy-js-api 弃用告警
这是既有 scss 写法与新版 dart-sass 的差异,告警不影响退出码,也不影响产物。
H5
pnpm dev:h5 / pnpm build:h5 仍在 package.json 里,但不在承诺范围内。