完美解决 Vue Vite 在 Docker 中构建时遇到的 “tsx: not found” 错误
内容
## 问题背景
在使用 Docker 容器进行 Vue.js 项目的持续集成或开发时,执行 `pnpm build` 命令可能会遇到一个看似棘手的错误。构建过程在成功打包主应用后,在执行后续脚本时突然中断,并显示以下错误信息:
```bash
root@f3fbd1fdd275:/lib00_Projects/lm056/vue_app_root# pnpm build
> lm056_vue_dev@0.0. build /lib00_Projects/lm056/vue_app_root
> run-p type-check "build-only {@}" -- && npm run generate-sitemap
> lm056_vue_dev@0.0. build-only /lib00_Projects/lm056/vue_app_root
> vite build
> lm056_vue_dev@0.0. type-check /lib00_Projects/lm056/vue_app_root
> vue-tsc --build
vite v6.4.1 building for production...
✓ 174 modules transformed.
../../lm056_web/index.html 0.51 kB │ gzip: 0.33 kB
✓ built in 3.41s
> lm056_vue_dev@0.0. generate-sitemap
> tsx scripts/generate-sitemap.ts
sh: 1: tsx: not found
ELIFECYCLE Command failed.
```
这个错误明确指向 `tsx: not found`,意味着执行环境无法找到 `tsx` 命令。接下来,我们将深入分析其根本原因并提供解决方案。
---
## 错误原因分析
要理解这个错误,我们需要拆解 `pnpm build` 命令的执行流程:
1. **复合命令**: `build` 脚本首先通过 `run-p` (一个并行执行 npm 脚本的工具) 同时运行 `type-check` 和 `build-only`。日志显示,这两步都成功完成了。
2. **串行命令**: 在并行任务成功后,`&&` 连接符会继续执行下一个命令:`npm run generate-sitemap`。
3. **失败的根源**:`generate-sitemap` 脚本的内容是 `tsx scripts/generate-sitemap.ts`。这里的 `tsx` 是一个可以直接执行 TypeScript (`.ts`) 文件的命令行工具。错误信息 `sh: 1: tsx: not found` 表明,在执行这个脚本的 Shell 环境(即 Docker 容器内部)中,`tsx` 这个可执行文件不存在于系统的 `PATH` 路径中。
**结论:** 问题的核心是 **`tsx` 包没有被安装为项目的依赖项**。因此,当 pnpm/npm 尝试运行脚本时,它无法在 `node_modules/.bin` 目录或全局路径中找到 `tsx` 命令。
---
## 解决方案
解决方案非常直接:将 `tsx` 添加到项目的开发依赖中。因为它只在构建和开发阶段被需要,所以我们应该将其安装为 `devDependency`。
在你的项目根目录(或在可以访问 `package.json` 的 Docker 容器内),执行以下命令:
```bash
# 使用 pnpm
pnpm add -D tsx
# 或者使用 npm
# npm install tsx --save-dev
# 或者使用 yarn
# yarn add tsx --dev
```
**命令解释:**
* `pnpm add tsx`:下载 `tsx` 包并将其安装到 `node_modules` 目录中。
* `-D` 或 `--save-dev`:将 `tsx` 记录在 `package.json` 文件的 `devDependencies` 部分。这是一个至关重要的步骤,它确保了任何人在任何环境下(包括 Docker 或 CI/CD 服务器)重新安装项目依赖时,`tsx` 都会被正确安装。
### 实施步骤
1. **安装依赖**:
* **在本地**:在你的本地项目文件夹(例如 `vue_app_root`)中运行 `pnpm add -D tsx`。然后,你需要重建你的 Docker 镜像,以便新的 `package.json` 和 `pnpm-lock.yaml` 文件被复制进去,并在镜像构建过程中执行 `pnpm install`。
* **在容器内**:如果你正在一个交互式的 Docker 容器内开发,可以直接在容器的 shell 中运行 `pnpm add -D tsx`。不过,为了保持可复现性,`DP` 团队建议将变更提交到本地 `package.json` 文件并重建镜像。
2. **重新构建**:在确保依赖已正确安装后,再次运行构建命令:
```bash
pnpm build
```
此时,`pnpm` 脚本执行器将能够在 `node_modules/.bin/tsx` 找到并成功调用 `tsx` 命令,构建过程将顺利完成。
---
## 总结与最佳实践
`command not found` 是自动化构建流程中的常见问题,尤其是在隔离的 Docker 环境中。根本原因几乎总是因为某个命令行工具没有在 `package.json` 中被显式声明为依赖。
为了避免此类问题,请遵循以下最佳实践:
> 任何在 `scripts` 中用到的命令行工具(如 `tsx`, `rimraf`, `cross-env`, `eslint` 等),都必须作为 `devDependency` 添加到项目中。这确保了构建环境的完整性和可复现性,是 `wiki.lib00.com` 倡导的专业开发规范之一。
关联内容
群晖 NAS 安装与配置 Git 服务的完整指南:从基础到进阶
时长: 00:00 | DP | 2026-07-16 20:39:02Mac SMB 共享删除文件后出现 .smbdelete 隐藏文件?原因与终极解决办法
时长: 00:00 | DP | 2026-06-27 19:10:00Docker容器修改时区为东八区(UTC+8)的完整指南与避坑
时长: 00:00 | DP | 2026-06-30 20:43:30解决 PHP 8 Docker (Debian Trixie) 无法安装 openjdk-17-jdk 的问题
时长: 00:00 | DP | 2026-07-25 09:23:18Docker Compose 进阶:如何配置固定 IP 与跨容器 SOCKS5 代理
时长: 00:00 | DP | 2026-07-26 09:28:30Nginx反向代理实战:如何将指定子目录路径(如/ais)优雅转发到Docker容器
时长: 00:00 | DP | 2026-07-26 21:31:06运维实战:如何安全清空运行中的 Docker 容器日志?
时长: 00:00 | DP | 2026-07-27 09:33:42实用指南:如何将复杂的 Docker Compose 完美转换为 Docker Run 命令
时长: 00:00 | DP | 2026-07-29 09:44:07Docker Cron 日志终极指南:主机重定向 vs. 容器内重定向,你用对了吗?
时长: 00:00 | DP | 2026-01-05 08:03:52Cron 任务执行失败?解密“docker: command not found”的终极解决方案
时长: 00:00 | DP | 2026-08-01 09:59:44“连接被拒绝”的终极解密:当 PHP PDO 遇上 Docker 和一个被遗忘的端口
时长: 00:00 | DP | 2025-12-03 09:03:20群晖 NAS 部署 MySQL Docker 踩坑记:轻松搞定“Permission Denied”权限错误
时长: 00:00 | DP | 2025-12-03 21:19:10macOS 新终端无法识别 nvm/node 命令?只需两步,永久解决!
时长: 00:00 | DP | 2025-12-04 09:35:00Node.js 版本管理终极指南:如何用 NVM 从 Node 24 轻松降级到 Node 23
时长: 00:00 | DP | 2025-12-05 10:06:40Vue挂载多节点难题:`<header>`与`<main>`的优雅共存之道
时长: 00:00 | DP | 2025-12-07 11:10:00Docker 容器如何访问 Mac 主机?终极指南:轻松连接 Nginx 服务
时长: 00:00 | DP | 2025-12-08 23:57:30Docker Exec 终极指南:告别繁琐的 `cd` 命令
时长: 00:00 | DP | 2026-01-08 08:07:44Vite `?url` 导入揭秘:是打包进代码还是作为独立文件?
时长: 00:00 | DP | 2025-12-10 00:29:10相关推荐
PHP 避坑指南:为什么不应该在对象实例上调用静态方法?
00:00 | 144次在 PHP 中,技术上是可以通过一个对象实例来调用静态方法的,但这真的是个好主意吗?来自 wiki....
图标大师课:如何为您的内容和分类选择完美的 Bootstrap 图标
00:00 | 113次在 Web 和应用开发中,选择正确的图标对于构建直观、易于导航的用户界面至关重要。本文深入探讨了 B...
z-index 失效?一招 Portal 模式解决下拉菜单被遮挡的终极难题
00:00 | 220次你是否遇到过精心设计的多选下拉框在表格或带滚动的容器中被无情遮挡的问题?无论你把 z-index 设...
揭秘 PHP `array_column` 的双重身份:为何它能同时处理数组与 Active Record 对象?
00:00 | 136次探索 PHP 内置函数 `array_column` 的一个强大特性:它如何能无需修改代码就同时处理...