Monorepo 中的 Astro 5 Glob Loader Bug
你的 Astro 构建通过了。零错误。零警告。但你的内容却丢失了。
我最近在 pnpm monorepo 中遇到了这个问题。我当时正在使用 Astro 5 的 content collections 为页面添加编辑观点(editorial takes)。在本地,一切运行完美。但在我的 CI 流水线中,页面渲染出的内容却是空的。
问题在于 glob loader 解析路径的方式。
问题所在
Astro 的 glob loader 从 process.cwd() 解析相对基准路径。它并不使用你的配置文件所在的位置。
在 monorepo 中,你的 CI 通常从工作区根目录(workspace root)运行构建。而在本地,你可能是在应用目录(app directory)下运行构建。
- 本地:cwd 是
apps/oss-alternatives。路径./content可以正常工作。 - CI:cwd 是仓库根目录。路径
./content不存在。
当 Astro 找不到文件时,它不会抛出错误。它只是简单地返回一个空集合。你会发布一个数据缺失的网站,却对此一无所知。
解决方案
不要再使用相对字符串来表示路径。使用 import.meta.url 将路径锚定到配置文件,而不是工作目录。
使用以下模式:
import { fileURLToPath } from "node:url";
const TAKES_DIR = fileURLToPath(
new URL("./content/per-alternative-takes", import.meta.url)
);
这确保了无论你从哪里运行构建,路径始终是正确的。
避免 ID 冲突
默认情况下,glob loader 使用 frontmatter 中的 slug 字段作为 ID。如果用户添加了 slug 字段,可能会破坏你的数据查询。请使用 generateId 来强制将文件名作为权威 ID。
给 Monorepo 开发者的经验教训
- 在本地从工作区根目录运行冒烟测试(smoke tests)。如果你只在应用文件夹中进行测试,你将会错过路径相关的 bug。
- 添加集合健康检查。在你的开发环境中,如果关键集合返回的项目数为零,请抛出错误。
- 在配置文件中的每个文件引用都使用绝对路径解析。
- 添加部署后检查,以验证关键内容是否存在于线上 HTML 中。
永远不要相信沉默。构建成功并不总是意味着部署成功。
