Viteエイリアスが`@plugin`のパッケージ解決を壊す問題を修正

tailwindlabs/tailwindcss

@tailwindcss/vite 4.2.3で追加されたVite aliasesサポートが、@をエイリアスとして使う環境で@tailwindcss/typography等のパッケージ解決を破壊していた問題を修正しました。Viteのリゾルバーが絶対パスを返せない場合は@tailwindcss/nodeのフォールバック解決に委ねる処理を追加しています。

背景

4.2.3でViteのresolve.aliasオプションに対応したことで、エイリアス経由のパス解決が可能になりました。しかし@という単一文字をエイリアスとして登録している場合、@tailwindcss/typographyのようなパッケージ名のプレフィックスとも衝突してしまいます。

Viteのリゾルバーは@tailwindcss/typography@エイリアスで解釈しようとしますが、ローカルファイルとして解決できないため失敗します。#19946では、vite.configに以下のようなエイリアス設定を持つユーザーがビルドエラーを報告しています。

resolve: {
  alias: [
    { find: '@', replacement: fileURLToPath(new URL('.', import.meta.url)) },
  ],
}

この設定自体は一般的なプロジェクトルートエイリアスですが、4.2.3以前は正常に動作していたため、リグレッションとして報告されました。

技術的な変更

packages/@tailwindcss-vite/src/index.tscustomCssResolvercustomJsResolver に、Viteのリゾルバー結果を検証するガード処理を追加しました。

変更前:

customCssResolver = async (id: string, base: string) => {
  let resolved = await cssResolver(id, base, false, isSSR)
  if (resolved && !resolved.endsWith('.css')) return undefined
  return resolved
}
customJsResolver = (id: string, base: string) => jsResolver(id, base, false, isSSR)

変更後:

customCssResolver = async (id: string, base: string) => {
  let resolved = await cssResolver(id, base, false, isSSR)
  if (!resolved) return
  if (resolved === id) return
  if (!path.isAbsolute(resolved)) return
  if (!resolved.endsWith('.css')) return
  return resolved
}
customJsResolver = async (id: string, base: string) => {
  let resolved = await jsResolver(id, base, false, isSSR)
  if (!resolved) return
  if (resolved === id) return
  if (!path.isAbsolute(resolved)) return
  return resolved
}

追加されたガード条件は3つです:

  • resolved === id: リゾルバーが入力をそのまま返した場合(解決できていない)
  • !path.isAbsolute(resolved): 絶対パスでない場合(エイリアスが部分的にしか展開されていない)
  • 以前からある !resolved.endsWith('.css'): CSS以外のファイルへの解決をCSSリゾルバーで弾く

これらのガードを抜けない場合はundefinedを返し、@tailwindcss/nodeの解決ロジックへのフォールバックを促します。同様のロジックはEnvironment APIを使うコードパス(elseブランチ)にも対称的に適用されています。

またcustomJsResolverは従来同期関数として定義されていましたが、今回の変更でasync関数に統一されました。

設計判断

Viteのリゾルバーを信頼する条件として「絶対パスへの変換」を必須とする設計が採用されました。

Viteのエイリアスリゾルバーは、エイリアスにマッチしない識別子(例:@tailwindcss/typographyのうち@がエイリアスにマッチするケース)を処理した際、絶対パスではなく元の識別子や相対パスに近い値を返すことがあります。path.isAbsolute()によるチェックはこの曖昧さを排除し、「Viteが確実にファイルシステム上のパスへ解決できた」場合のみViteの結果を採用するシンプルかつ堅牢な判定基準となっています。フォールバック先の@tailwindcss/nodeはNode.jsのモジュール解決に従うため、npmパッケージの解決はそちらに委ねられます。

まとめ

Viteのリゾルバー結果に「絶対パスであること」という検証を加えることで、エイリアスの部分マッチによる誤解決を防ぎつつ、npmパッケージの解決はNode.jsの機構に委ねる責務分離が実現されています。@import@pluginの両方に同じガードが適用されたことで、Viteエイリアスとパッケージ名が共存する環境での信頼性が向上しました。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
c08c9b3f

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

「リード文→背景→技術詳細→設計判断→まとめ」という総論→各論→結論の構成が明確であり、ガイドラインに完全に準拠しています。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト(`ts:vite.config.ts`など)とGitHubリンク記法(PR/Issue番号)が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

ViteやTailwind CSSに関する専門的な内容であり、対象読者であるエンジニアに適した技術レベルと表現で記述されています。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが要約から始まり、各段落がトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られており、非常に高い可読性を実現しています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内で引用されているコードブロック(`vite.config.ts`, `packages/@tailwindcss-vite/src/index.ts`)は、提供されたDiff情報と正確に一致しています。変更点の要点も的確に抽出されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「Vite resolver」「absolute path」「fallback」などの技術用語が、文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

「絶対パスが返せない場合にフォールバックする」という変更の核心的なロジックについて、技術的に正確かつ分かりやすく説明されています。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張(問題の背景、技術的な変更内容、設計判断)は、PRのDescriptionやDiff内のコードによって裏付けられており、ハルシネーションは検出されませんでした。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#19947)、Issue番号(#19946)、バージョン番号(4.2.3)などの数値や固有名詞はすべて正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトルはPR「Fix issue around resolving paths in `@tailwindcss/vite`」の内容をより具体的に、かつ正確に表現しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事の内容はすべて提供されたPR情報とDiffに基づいており、サポート状況やリリース予定など、PR外の知識の追記はありません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「破壊していた問題を修正しました」といった過去形の表現が、PRの文脈と一致しており、時間表現は正確です。