モノレポにおける Astro 5 Glob Loader のバグ

Astro のビルドは成功しました。エラーはゼロ。警告もゼロ。しかし、コンテンツが欠落しています。

最近、pnpm モノレポでこの問題に直面しました。Astro 5 の content collections を使用して、ページにエディトリアルな見解(editorial takes)を追加していました。ローカルではすべて完璧に動作していました。しかし、CI パイプラインでは、ページが空のコンテンツでレンダリングされてしまいました。

問題は、glob loader がパスをどのように解決するかという点にあります。

問題点

Astro の glob loader は、process.cwd() を基準として相対的なベースパスを解決します。設定ファイルの場所は使用しません。

モノレポでは、CI は多くの場合、ワークスペースのルートからビルドを実行します。一方、ローカルでは通常、アプリのディレクトリからビルドを実行しているはずです。

  • ローカル: 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 は、デフォルトでフロントマターの slug フィールドを ID として使用します。ユーザーが slug フィールドを追加すると、データのルックアップが壊れる可能性があります。generateId を使用して、ファイル名を決定的な ID として強制してください。

モノレポ開発者のための教訓

  • ローカルではワークスペースのルートからスモークテストを実行する。アプリフォルダからのみテストしていると、パスのバグを見逃してしまいます。
  • コレクションのヘルスチェックを追加する。開発環境において、重要なコレクションが 0 件のアイテムを返した場合はエラーを投げるようにします。
  • 設定ファイル内のすべてのファイル参照に絶対パス解決を使用する。
  • 公開後の HTML に主要なコンテンツが存在することを確認するための、ポストデプロイ・チェックを追加する。

「沈黙」を信じてはいけません。ビルドが成功したからといって、必ずしもデプロイが成功しているとは限らないのです。

出典: https://dev.to/morinaga/what-i-learned-about-astro-5-glob-loader-path-resolution-in-a-pnpm-monorepo-2ed4