Taro 4 项目从 npm 迁移到 pnpm 踩坑实录

Taro 4 项目从 npm 迁移到 pnpm 踩坑实录

最近将一个基于 Taro 4 + React + TDesign 的微信小程序项目从 npm 迁移到 pnpm,原本只是想利用 pnpm 的依赖缓存机制提升安装效率,减少磁盘占用。

没想到迁移过程中连续遇到了几个问题:先是开发环境无法启动,修复后又出现微信小程序上传缺少依赖,最后上传阶段不断在不同的 JS 文件上报 undefined 错误。

项目主要依赖版本如下:

依赖 版本
Taro 4.3.0
pnpm 12.18.0
React 18.3.1
TDesign Miniprogram 1.16.0
@tarojs/plugin-mini-ci 4.3.1
miniprogram-ci 1.9.17
Webpack 5.91.0

迁移后,首先使用 pnpm 安装项目依赖:

复制代码
pnpm install

依赖安装过程没有明显异常,但运行微信小程序开发命令时:

复制代码
pnpm dev:weapp

却发现项目无法正常启动。

为了排查问题,将终端日志重定向到文件:

lua 复制代码
pnpm dev:weapp *> pnpm-error.log

打开 pnpm-error.log 后发现,Taro 生成的 Webpack 配置中,@tarojs/runtime 和 @tarojs/shared 的解析结果都是 null,导致 Webpack 无法正常启动。

这是迁移中遇到的第一个问题。

解决开发环境启动问题后,继续执行微信小程序上传命令:

arduino 复制代码
pnpm run build:weapp:upload

这次又出现了新的错误:

复制代码
请安装依赖:miniprogram-ci

补齐依赖后,构建可以正常完成,但上传阶段又陆续出现以下错误:

vbnet 复制代码
done: app.js
processing: miniprogram_npm/tdesign-miniprogram/button/index.js

错误 上传失败
app.js: undefined

[ELIFECYCLE] Command failed with exit code 1.

再次执行,报错文件可能变成:

bash 复制代码
错误 上传失败
miniprogram_npm/tdesign-miniprogram/badge/badge.js: undefined

甚至是:

javascript 复制代码
错误 上传失败
common.js: undefined

这些错误并不是同一个文件固定报错,容易让人误以为是 TDesign 组件、Webpack 编译产物或者微信小程序上传工具本身出现了问题。

经过逐步排查,最终的处理方式是:显式补充 Taro 依赖、安装小程序 CI 上传依赖,以及调整 pnpm 的依赖布局模式。

解决方案

1. 解决 Webpack 无法解析 Taro 依赖的问题

迁移后,首先遇到的问题是:

复制代码
pnpm dev:weapp

无法正常启动。

通过 PowerShell 将日志保存到文件:

lua 复制代码
pnpm dev:weapp *> pnpm-error.log

在日志中发现,Taro 生成的 Webpack 配置里,两个模块的解析结果为 null:

less 复制代码
@tarojs/runtime: null
@tarojs/shared: null

pnpm 默认采用严格的依赖隔离机制。与 npm 相对扁平的 node_modules 不同,pnpm 不会默认让所有间接依赖都能被项目直接访问。

如果项目或构建工具需要直接解析某些依赖,但项目没有显式声明,就可能出现模块解析失败。

针对这次遇到的问题,直接安装与当前 Taro 版本一致的依赖:

sql 复制代码
pnpm add @tarojs/runtime@4.3.0 @tarojs/shared@4.3.0

安装完成后,重新启动:

复制代码
pnpm dev:weapp

此时开发环境恢复正常。

需要注意的是,@tarojs/runtime 和 @tarojs/shared 应尽量与项目中的 @tarojs/taro 保持版本一致,避免引入额外的版本冲突。

2. 解决微信小程序上传缺少 miniprogram-ci 的问题

开发环境启动成功后,继续执行上传:

arduino 复制代码
pnpm run build:weapp:upload

项目对应的脚本配置为:

json 复制代码
{
  "scripts": {
    "dev:weapp": "taro build --type weapp --watch",
    "build:weapp": "taro build --type weapp",
    "build:weapp:upload": "taro build --type weapp --upload"
  }
}

但执行时提示:

复制代码
请安装依赖:miniprogram-ci

这是因为 Taro 的小程序 CI 上传流程需要使用 miniprogram-ci。

在 npm 环境中,某些依赖可能通过间接依赖的方式被访问到;迁移到 pnpm 后,这类未显式声明的依赖更容易暴露出来。

解决方式是将 miniprogram-ci 显式安装为开发依赖:

sql 复制代码
pnpm add -D miniprogram-ci@1.9.17

这里使用的是本次项目的版本。其他项目应根据当前 Taro CI 插件的兼容要求选择对应版本。

安装完成后,再次执行:

arduino 复制代码
pnpm run build:weapp:upload

这次不再提示缺少 miniprogram-ci,但又出现了新的上传错误。

3. 解决上传阶段 JS 文件报 undefined 的问题

安装 miniprogram-ci 后,项目已经能够正常编译,但在上传阶段出现:

javascript 复制代码
错误 上传失败
app.js: undefined

随后多次尝试,错误文件又变成:

bash 复制代码
miniprogram_npm/tdesign-miniprogram/badge/badge.js: undefined

或者:

javascript 复制代码
common.js: undefined

这里有两个比较明显的特点:

  • Taro 构建可以正常完成,问题集中在上传流程。
  • 报错涉及不同的 JS 文件,并不是某个固定组件始终编译失败。

这时需要考虑 pnpm 与 npm 在依赖布局上的差异。

pnpm 默认使用 isolated 模式,通过虚拟存储目录及链接管理依赖,安装后通常可以看到:

kotlin 复制代码
node_modules/
├── .pnpm/
│   ├── @tarojs+cli@4.3.0/
│   ├── miniprogram-ci@1.9.17/
│   └── ...
├── @tarojs/
└── tdesign-miniprogram/

这种机制可以严格管理依赖关系,但部分原本依赖传统扁平化 node_modules 结构的工具链,可能存在兼容性问题。

对于从 npm 迁移而来的老项目,可以尝试将依赖布局切换为 hoisted 模式。

本次使用的是 pnpm 12,需要在项目根目录使用 pnpm-workspace.yaml 管理对应配置。

首先执行:

arduino 复制代码
pnpm config set --location=project nodeLinker hoisted

然后检查:

arduino 复制代码
pnpm config get nodeLinker

期望得到:

复制代码
hoisted

也可以直接打开项目根目录的 pnpm-workspace.yaml,添加:

makefile 复制代码
nodeLinker: hoisted

如果文件已经存在,只需要添加对应字段,不要覆盖原有的 workspace 配置。

hoisted 模式会让 pnpm 使用更接近 npm 的扁平化依赖布局,从而减少部分工具链在依赖路径解析方面的兼容问题。

修改配置后,需要重新安装依赖才能应用新的布局。

在 Windows PowerShell 中执行:

复制代码
Remove-Item -Recurse -Force node_modules
pnpm install

这里建议保留 pnpm-lock.yaml,避免因为重新解析依赖版本而引入其他变量。

完成后重新构建:

arduino 复制代码
pnpm run build:weapp

再执行上传:

arduino 复制代码
pnpm run build:weapp:upload

本次迁移中的上传问题最终通过调整 nodeLinker 为 hoisted 得到解决。

需要说明的是,这种处理方式说明依赖布局与问题有关,但不能仅凭 undefined 错误认定 miniprogram-ci 内部的具体故障原因。

4. 将 pnpm 配置保存到项目

为了避免其他开发者重新安装依赖后再次遇到相同问题,建议将项目级配置一并提交到 Git。

项目根目录保留:

makefile 复制代码
# pnpm-workspace.yaml
nodeLinker: hoisted

同时可以在 package.json 中声明包管理器版本:

perl 复制代码
{
  "packageManager": "pnpm@12.18.0"
}

这样团队成员和 CI 环境可以尽量保持一致的 pnpm 版本及依赖安装行为。

需要注意,hoisted 并不是 pnpm 的默认推荐模式,也不是所有 Taro 项目的必需配置。对于新项目,仍然可以优先使用默认的依赖隔离模式。

相关推荐
前端小D21 分钟前
JS核心底层
前端·javascript
用户308169987648532 分钟前
同一句话问 AI 15 次,答案 15 个:temperature 0 实测也不稳
前端
SameX35 分钟前
ArkTS 做 5 态数据流 —— 咖啡电量的代谢状态机怎么驱动 UI
前端
Dovis(誓平步青云)36 分钟前
启元 T1 Pro 人机相声搭档:语音-触摸双通道的启元机器人节奏引擎设计
开发语言·前端·javascript·microsoft·交互
爱吃烧烤的技术渣39 分钟前
别再手写 CRUD 了:我把 Element Plus 的工作量压缩成一份列 schema
前端·vue.js
MetWeave42 分钟前
风的三十年:一个机场的风在变小吗:10,958 天的账(《风不是一个数》系列第 6 篇)
前端·数据可视化
青烟小生1 小时前
前端实时协同编辑与 CRDT 冲突解决实战:从 OT 到 Yjs 底层原理(完整版)
前端
陈随易1 小时前
神级 Skill,让 AI 用 HTML 代替 Markdown 回复
前端·后端·程序员
eidnxndrdkdns1 小时前
PE 自校验的三个坑:恒失败、基址变化、以及被漏在外面的检测器
前端