PostCSS の `from` 未設定時にプロジェクトルート外を参照するバグを修正
@tailwindcss/postcss プラグインが result.opts.from を受け取らない環境で、インポート解決のベースパスがプロジェクトルートの親ディレクトリになってしまうバグが修正されました。Turbopack を含む一部のバンドラーで発生していた Can't resolve 'tailwindcss' エラーが解消されます。
背景
PostCSS プラグインは必ずしも from オプションを受け取るとは限らず、Turbopack を含む一部のバンドラーは特定の CSS 入力に対して from なしでプラグインを呼び出します。この状況では result.opts.from が undefined となり、inputFile が空文字列 '' になります。
問題の核心は Node.js の path.resolve('') の挙動にあります。path.resolve('') は process.cwd() を返し、さらに path.dirname(process.cwd()) はカレントディレクトリの親を返します。結果として compileAst({ base: inputBasePath }) がプロジェクトルートの1つ上のディレクトリから tailwindcss を解決しようとし、以下のエラーが発生していました。
Can't resolve 'tailwindcss' in '<parent of CWD>'
プラグイン自体はオプション解析の早い段階で base = opts.base ?? process.cwd() を計算しており、この値を再利用することで適切なフォールバックが実現できます。
技術的な変更
packages/@tailwindcss-postcss/src/index.ts の inputBasePath 計算に1行の三項演算子が追加されました。
変更前:
let inputBasePath = path.dirname(path.resolve(inputFile))
変更後:
let inputBasePath = inputFile ? path.dirname(path.resolve(inputFile)) : base
inputFile が空文字列(falsy)の場合に限り、既に算出済みの base 変数をそのまま inputBasePath として使用します。base は opts.base ?? process.cwd() で定められているため、ユーザーが opts.base を明示した場合はその値が、省略した場合は process.cwd()(プロジェクトルート)が使われます。
テストは packages/@tailwindcss-postcss/src/index.test.ts に追加されています。from オプションなしで processor.process('@import \'tailwindcss\'') を呼び出し、修正前は例外を投げていた箇所で非空の CSS が返されることを検証しています。
test('fallback to `base` directory when `result.opts.from` is not provided', async () => {
let processor = postcss([
tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }),
])
let result = await processor.process(`@import 'tailwindcss'`)
expect(result.css.length).toBeGreaterThan(0)
})
設計判断
プラグイン上部で既に算出済みの base 変数を再利用するアプローチが採用されました。
PR の説明に記されているように、この変更の意図は「sensible default (CWD) を与えつつ、明示的な opts.base が設定されている場合はそれを尊重する」ことです。base = opts.base ?? process.cwd() という既存のロジックがまさにこの要件を満たしており、新たなロジックを追加することなく再利用することで実現しています。
変更は1行の条件分岐追加のみであり、from が存在する通常ケースのコードパスは一切変更されていません。影響範囲は from が省略される環境に限定されるため、既存の動作に対するリグレッションリスクは最小限です。
まとめ
path.resolve('') が process.cwd() を返し path.dirname でさらに1階層上がるという Node.js のパス解決の挙動を、プラグイン設計の文脈で正しく扱うための修正です。1行の変更でありながら、opts.base による明示設定の尊重とデフォルト動作の正確化を同時に達成しており、PostCSS プラグインの堅牢な設計指針を示す好例といえます。