@source グロブで `**/*` 終端の動的パスを保持し過剰スキャンを防止
Tailwind CSS の @source 指令が **/* で終わるパターンを変換する際、動的セグメント(*)を失ってベースディレクトリだけで自動スキャンを行っていた問題を修正し、不要なファイル走査を削減しました。
背景
@source が **/* 終端かつ途中にワイルドカードを含む場合、以前はベースパスだけが SourceEntry::Auto として扱われ、パターン情報が失われていました。例えば @source './blog/*/foo/bar/baz/**/*' は Auto { base = ".../blog" } に変換され、foo/bar/baz 以下の限定が失われ、blog 配下のすべてを走査していたため、実行時に数千件のファイルを無駄に読んでいました。この過剰スキャンはデバッグ時に tailwindcss_oxide::scanner のログで顕在化し、#20214 の既存修正でも同様のディレクトリ無視問題が指摘されていましたが、動的パス保持は別途対策が必要でした。
技術的な変更
sources.rs の変換ロジック が修正され、value.pattern == "/**/*" または PathBuf::from(&value.base).join(&value.pattern).is_dir() のみで Auto 判定を行うようになりました。これにより **/* 終端でも他に動的要素がある場合は Auto へは転換されず、SourceEntry::Pattern が生成されます。
- let auto = value.pattern.ends_with("**/*")
- || PathBuf::from(&value.base).join(&value.pattern).is_dir();
+ let auto =
+ value.pattern == "/**/*" || PathBuf::from(&value.base).join(&value.pattern).is_dir();
Pattern エントリ生成 ではベースに静的ディレクトリ(blog)だけを残し、残りのセグメント (/*/foo/bar/baz/**/*) を pattern フィールドに保持します。結果として次のように変換されます。
SourceEntry::Pattern {
base: "/Users/.../blog",
pattern: "/*/foo/bar/baz/**/*"
}
テストケース が追加され、@source './blog/*/foo/bar/baz/**/*' に対して期待通り candidates に blog/*/foo/bar/baz/**/* が残ることを検証しています。
+ #[test]
+ fn it_should_preserve_paths_for_sources_ending_in_a_deep_glob() {
+ let ScanResult { candidates, files, globs, normalized_sources } =
+ scan_with_globs(&[ ("blog/2024/foo/bar/baz/index.html", "content-['blog/2024/foo/bar/baz/index.html']"), ("blog/2024/foo/bar/qux/index.html", "content-['blog/2024/foo/bar/qux/index.html']") ],
+ vec!["@source './blog/*/foo/bar/baz/**/*'"]);
+ assert_eq!(candidates, vec!["content-['blog/2024/foo/bar/baz/index.html']"]);
+ assert_eq!(files, vec!["blog/2024/foo/bar/baz/index.html"]);
+ assert_eq!(globs, vec!["blog/*/foo/bar/baz/**/*"]);
+ assert_eq!(normalized_sources, vec!["blog/*/foo/bar/baz/**/*"]);
+ }
設計判断
Auto への過剰変換を防止 するために、パターンが完全に固定されたケース(/**/* のみ)だけを Auto とみなす方針が採用されました。この判断は既存の Auto エントリが自動コンテンツ検出をトリガーし、すべてのサブパスを走査する特性を踏まえ、動的パス情報を失うリスクが高い 場面での使用を回避することを意図しています。結果として 後方互換性 は保たれ、@source './blog/**/*' のような純粋なベース指定は従来通り Auto に変換されます。一方、* を含む深いグロブは Pattern に変換され、スキャン対象が限定されます。
まとめ
この PR は @source の **/* 終端パターンで動的セグメントがある場合に パターン情報を保持 し、SourceEntry::Pattern として扱うことで不要なファイル走査を防止しました。ベースディレクトリの自動検出は維持しつつ、動的パスの精度向上によりスキャン効率が大幅に改善されます。