构建配置与缓存:让 Pages 每次构建都可复现
读完这篇你能做到:把 Pages 的构建配置调到一个可复现的状态,知道每个字段影响什么,明白依赖缓存省下的时间从哪来,并且在"本地能构建、云端失败"时有一份确定的排查顺序。
适用的场景是 Git 集成方式部署,也就是云端执行构建命令的那条路径。用 wrangler pages deploy 直接传产物的,构建发生在你自己的机器或 CI 上,这篇里的环境变量一节仍然值得看一眼。
1. 四个核心字段
| 字段 | 作用 | 常见错误 |
|---|---|---|
| Root directory | 命令在哪个目录执行 | 仓库是 monorepo,填了根目录导致找不到 package.json |
| Build command | 安装依赖之外的构建动作 | 把 npm install 也写进去,和平台的自动安装重复 |
| Build output directory | 上传哪个目录 | 写成源码目录,把 src 也传了上去 |
| Build watch paths | 只有这些路径变化才触发构建 | 留空,改文档也触发一次构建 |
Root directory 在 monorepo 里最容易出问题。仓库结构是 apps/web 加 packages/ui 时,根目录要填 apps/web,输出目录填 dist(相对根目录),而不是 apps/web/dist。
Build command 里不需要写 npm install。平台在跑构建命令之前会自己装依赖,重复写一次只会让构建变慢;除非你要装的是平台识别不到的东西。
Build watch paths 是省构建次数的开关。一个仓库里既有站点又有文档时,把它设成 src/* 之类,改 README 就不会消耗那 500 次月度额度。
2. Node 版本与包管理器
平台按 lock 文件判断包管理器:有 pnpm-lock.yaml 用 pnpm,有 yarn.lock 用 yarn,有 package-lock.json 用 npm。三种文件同时存在时行为取决于平台的探测顺序,删掉多余的最省事。
Node 版本用环境变量固定:
NODE_VERSION=20
不写也能构建,但默认版本会随平台镜像更新而变。某天构建突然因为某个依赖要求更高版本而挂掉,通常就是这里没锁。
pnpm 项目还要注意版本:packageManager 字段写进 package.json 比在环境变量里指定更稳。
3. 两类环境变量别混
| 类型 | 何时可用 | 是否会暴露 |
|---|---|---|
| 构建时变量 | 只在构建容器里 | 会被打进产物,前端代码能读到 |
| Functions 变量与密钥 | 只在请求处理时 | 不出现在产物里 |
把 API key 配成构建时变量,再在前端代码里 import.meta.env 读出来,等于把它公开在 JS 文件里。需要在浏览器里调第三方接口时,走服务端代理,密钥留在 Functions 的 context.env 里,写法见 68-pages-functions.md。
变量按环境区分:Production 与 Preview 各有一套。预览环境指向测试接口、生产环境指向正式接口,靠的就是这个区分。
4. 依赖缓存
平台会在多次构建之间保留依赖缓存,装过的包不必每次从 registry 重新下载。这就是为什么第一次构建要两三分钟,后续改动只改一个组件时可能几十秒就结束。
缓存命中依赖两件事:lock 文件没变、包管理器版本没变。改了 pnpm-lock.yaml 就会重新装一遍,这是正常现象,不是缓存失效。
缓存不覆盖构建产物。dist 每次都是新生成的,不存在"上次的旧文件混进来"的情况。
5. 分支不同,命令不同
预览环境需要和生产不同的构建参数时(比如预览站要开调试面板、指向测试 API),在项目 Settings 的 Builds & deployments 里可以给指定分支单独配命令与变量。
配置粒度是分支名,不是通配。分支命名建议固定成 main、dev、preview/* 这样的规则,配起来才不会漏。
6. 构建失败时的排查顺序
按这个顺序看,多数问题在前两步就能定位。
- 读构建日志的最后 30 行,找第一个
ERROR,不是最后一个。 - 本地用同样的 Node 版本跑一次
npm run build。对不上就是环境差异。 - 检查大小写。Linux 构建环境区分大小写,
import './Header'在 Windows 上能过,云端会失败,而本地文件名是header.vue。 - 检查 lock 文件是否提交进了仓库。没有 lock 文件时依赖版本可能和本地不一致。
- 检查输出目录是否存在。构建成功但目录为空,部署上去就是 404。
第 3 条是最常见的隐性原因。本地开发在 Windows 或 macOS 默认文件系统上不区分大小写,这个问题只在云端暴露。
常见问题
某次提交不想触发构建,怎么做。
在 commit message 里带上 [skip ci],平台会跳过这次构建。适合只改注释或文档、又不想占用月度额度的提交。
构建时要用私有 npm 包。
在仓库里放 .npmrc,把 registry 和认证 token 配好。token 建议放构建时环境变量而不是提交进仓库,.npmrc 里用变量引用。
为什么同一份代码两次构建结果不一样。
检查是否有依赖没锁版本(^ 开头的依赖加上无 lock 文件)、构建时是否读了当前时间或随机数、以及是否依赖了本地存在的文件但没提交。这三类都会让构建不可复现。
小结
构建配置的目标只有一个:让云端那次构建和你在本地跑出来的结果一致。做到这一点靠四件事,锁 Node 版本、提交 lock 文件、输出目录填对、变量分对环境。
依赖缓存是加速手段,不是正确性保障。它省掉的是下载时间,省不掉环境差异带来的问题,所以排查顺序里第三步永远是本地复现。
框架侧的具体命令(Astro 的 dist、Hugo 的 public)在 71-static-site-astro-hugo.md,构建额度与并发的完整对照在 56-free-tier-limits-cheatsheet.md。
数据来源与检索时间
检索时间 2026-11-10。
| 来源 | URL | 对应数据 |
|---|---|---|
| Pages Limits | https://developers.cloudflare.com/pages/platform/limits/ | 免费档每月 500 次构建、并发 1、单次构建 20 分钟超时 |
| Pages 构建配置文档 | https://developers.cloudflare.com/pages/configuration/build-configuration/ | 根目录、构建命令、输出目录、监视路径、NODE_VERSION 环境变量 |
| Pages 分支构建配置 | https://developers.cloudflare.com/pages/configuration/branch-build-controls/ | 按分支设置不同构建命令与变量 |
核验说明
- 文档部分:构建次数与超时来自 2026-11-10 抓取的 Pages Limits 页面。字段含义与
NODE_VERSION用法依据官方构建配置文档。 - 未执行:没有 Pages 项目,所有控制台配置项(根目录、监视路径、分支构建)未实际操作。
- 未执行:依赖缓存的实际命中效果未观测,缓存保留时长与容量未在文档中查到明确数字,因此正文没有给出具体时长。
- 未执行:
[skip ci]未在真实仓库验证,依据官方文档描述。 - 本地构建验证:无。这篇讨论平台侧配置,本机没有对应的构建产物可验证。