部署时集中爆出来的问题,大多在本地就已经存在,只是被开发服务和残留的依赖目录遮住了。判断「Void 能不能往部署走」,先过三道门槛:在一个干净目录里完整构建一次、用生产模式启动一次、确认运行时和依赖版本跟目标机器对得上。三件事都在本地做完,部署阶段剩下的才是真正的环境问题,而不是把构建问题拖到最后一起排查。下面每一步都给出可执行命令和验证方式,命令里的仓库地址、端口、构建脚本名需要按你手上的仓库替换。
先在本地跑通三道门槛再谈部署:干净目录里执行依赖安装和构建,确认退出码为 0,并知道失败时该看第一条报错而不是最后一条;用生产模式启动并实际访问首页和至少一个接口,记录状态码与返回体;对比本地与目标机器的运行时版本和锁文件安装结果。三步都通过只说明可构建、可启动、接口可达,不代表性能和稳定性达标,那需要在目标机器上继续观察。
在一个干净目录里完整跑一次构建命令
在已有目录里构建,很容易出现「假成功」:node_modules 里留着上一次装的旧包,构建通过但换台机器就失败。排除这种残留,最直接的办法是换一个空目录重新克隆、重新装依赖。
git clone <你的仓库地址> void-check
cd void-check
npm run
npm ci
npm run <构建脚本名>
echo $?
先执行 npm run 列出 package.json 里真实存在的脚本名,再选构建那一条,不要凭印象写 npm run build。包管理器不是 npm 时,把 npm ci 换成对应的锁文件安装命令:yarn 用 yarn install `--frozen-lockfile`,pnpm 用 pnpm install `--frozen-lockfile`。预期结果是构建命令退出码为 0,echo $? 输出 0;退出码非 0 就当作失败处理,不要因为产物目录里有文件就认为通过。
构建失败时,优先看的不是终端最后几行。按这个顺序找:第一行以 error 或 ERR! 开头的内容,它通常才是根因;编译器报错里第一条 error TS 或对应语言的第一个错误;堆栈里第一个指向你自己源码而不是 node_modules 的路径。最后几行往往只是「构建失败」的汇总提示,照着它排查容易跑偏。
用生产模式启动一次,而不是只跑开发服务
开发服务带热更新、带宽松的路径解析,很多问题不会暴露;生产模式下静态资源走打包产物、环境变量在启动前注入,路径写错、变量没传、依赖被当成开发依赖剔除,都会在这一步显形。所以本地至少要完整启动一次生产模式。
NODE_ENV=production PORT=3000 npm run start -- `--port` 3000
# 或在 .env / 配置文件中设置
# PORT=3000
生产启动脚本名同样以 npm run 的输出为准;参数形式随框架不同,有的读环境变量,有的读命令行参数,两种都写上便于对照。启动后用另开一个终端发请求,不要只看日志里那句「服务已启动」:
curl -i http://127.0.0.1:3000/
curl -i http://127.0.0.1:3000/api/health
第二个地址要换成你项目里真实存在的一个接口,没有健康检查接口就换一个只读接口。-i 是为了把状态码和响应头一起打出来:首页应返回 200 且 Content-Type 与预期一致,接口应返回你预期的状态码和一段可辨认的返回体。把这两次请求的状态码、Content-Type、返回体前几行抄到笔记里,作为这次「跑通」的证据;返回 404 或 500 时,先看启动日志里有没有路由未注册、静态目录找不到、环境变量为空的告警。
确认运行时与依赖版本在目标机器上一致
构建报错里混着两类问题:代码问题,和环境问题。把环境差异先剥离出去,剩下的报错才好判断。做法是在本地和目标机器上分别执行同一组检查命令,然后把输出并排比对。
node -v
npm -v
uname -a
npm ls `--depth`=0
比对的重点不是「版本号看着差不多」,而是三件事:Node 主版本是否一致(主版本不同,语法和内置模块行为可能不同);包管理器版本是否一致,因为它会影响依赖树的解析方式;npm ls `--depth`=0 列出的顶层依赖版本是否逐条对得上。原生模块还需要目标机器具备编译工具链,uname -a 用来确认系统与架构,跨架构时二进制依赖通常要重新安装。
锁文件(package-lock.json、yarn.lock、pnpm-lock.yaml 之一)的作用是把整棵依赖树的精确版本固定下来,安装时按它还原,而不是按 package.json 里的范围重新解析。所以锁文件要跟代码一起提交、一起同步到目标机器,并用 npm ci 这类严格按锁文件安装的命令;用 npm install 在版本范围允许时会更新锁文件,两端就容易装出不同的树。
把本次跑通的命令按顺序记录下来
跑通一次不等于下次还能跑通。把顺序记下来,换机器时照着执行,能省掉大量「上次是好的」的排查。下面是一份可以直接改的骨架,括号里的内容需要按你的环境替换。
git clone <仓库地址> void-check
cd void-check
npm ci
npm run <构建脚本名> # 退出码应为 0
NODE_ENV=production PORT=<端口> npm run <生产启动脚本名> -- `--port` <端口>
curl -i http://127.0.0.1:<端口>/
curl -i http://127.0.0.1:<端口>/<接口路径>
node -v && npm -v
标注清楚哪些是环境相关的:仓库地址、构建与启动脚本名(跟仓库的 package.json 走)、端口、接口路径、npm registry 或镜像配置、代理相关环境变量,以及目标机器上的 Node 与包管理器版本。这些参数换机器就要重新确认,其余命令可以原样复用。每次跑通后把实际输出(退出码、两个请求的状态码、版本比对结果)附在命令清单后面,下次出问题时第一件事就是拿新输出跟这份记录比,差异点通常就是问题所在。