Vite 7.1以降で外部ファイル監視時のフルリロードを復旧

tailwindlabs/tailwindcss

Vite 7.1で導入されたEnvironment APIの変更により、@sourceディレクティブで監視される外部ファイル(PHP、HTMLなど)の変更がフルページリロードをトリガーしなくなっていた問題が修正されました。@tailwindcss/viteプラグインが新しいHMR APIに対応し、テンプレートファイルの変更が再び正しくブラウザのリロードを引き起こすようになります。

背景

Tailwind CSS v4では、CSSファイル内の@sourceディレクティブでテンプレートファイルのパスパターンを指定できます。これにより、PHPやBladeなどの非標準ファイルもTailwindの監視対象に含められます。

@import "tailwindcss";
@source "../../**/*.php";

Vite 7.0.6以前では、これらのファイルを編集すると期待通りフルページリロードが発生していました。しかしVite 7.1以降では、ファイル変更時にCSS HMR更新のみが実行され、ページ全体のリロードが行われなくなっていました。#19637がこの問題を報告しています。

Vite 7.1で導入されたEnvironment APIが、この動作変更の原因です。従来のserver.ws.sendを使ったWebSocket APIが非推奨となり、server.hot.sendを使う新しいHMR APIへの移行が推奨されています。@tailwindcss/viteプラグインは旧APIのみに対応しており、Viteのモジュールグラフに含まれない外部ファイルの変更を新しい仕組みで伝播できていませんでした。

技術的な変更

packages/@tailwindcss-vite/src/index.tshotUpdateフックが追加され、外部ファイルの変更を検知してフルリロードを明示的にトリガーするようになりました。

hotUpdate({ file, modules, timestamp, server }) {
  // Viteのモジュールグラフに含まれないがTailwindが監視している
  // ファイル(PHP、HTMLなど)の変更時にフルリロードを発火
  let isExternalFile = modules.every((mod) => mod.type === 'asset' || mod.id === undefined)
  if (!isExternalFile) return

  for (let env of new Set([this.environment.name, 'client'])) {
    let roots = rootsByEnv.get(env)
    if (roots.size === 0) continue

    if (!isScannedFile(file, modules, roots)) {
      continue
    }

    let invalidatedModules = new Set<vite.EnvironmentModuleNode>()
    for (let mod of modules) {
      this.environment.moduleGraph.invalidateModule(
        mod,
        invalidatedModules,
        timestamp,
        true,
      )
    }

    // Vite 7.1+では server.hot.send、それ以前では server.ws.send
    if ('hot' in server && server.hot) {
      server.hot.send({ type: 'full-reload', path: '*', triggeredBy: file })
    } else if ('ws' in server && server.ws) {
      server.ws.send({ type: 'full-reload', path: '*' })
    }
  }
}

フックは変更されたファイルが外部ファイルtype === 'asset'またはid === undefined)かを判定します。addWatchFileで監視対象に追加されたファイルは、Viteのモジュールグラフには存在するものの、実際には処理されていない状態として扱われます。Vite 7.0.6ではtype: 'js'HARD_INVALIDATED状態で表現されていましたが、7.1以降ではtype: 'asset'となり、明示的なリロード処理が必要になりました。

外部ファイルと判定された場合、isScannedFileで実際にTailwindが監視しているファイルかを確認した上で、server.hot.sendまたはserver.ws.sendを使ってフルリロードを発火します。server.hotの存在確認により、Vite 7.1以降とそれ以前の両方に対応しています。

統合テストでは、Vite 6.x、7.0.8、7.1.12、7.3.1の各バージョンで動作を検証する体制が追加されました。

describe.sequential.each([['^6'], ['7.0.8'], ['7.1.12'], ['7.3.1']])(
  'Using Vite %s',
  (version) => {
    test('external source file changes trigger a full reload', {
      // テスト実装...
    })
  }
)

テストは、PHPファイルを@sourceで監視対象に追加し、そのファイルを編集した際にfull-reloadイベントが発生することを確認します。

設計判断

hotUpdateフックを実装する方式が採用されました。Viteの推奨する移行パスに従い、従来のhandleHotUpdateではなく新しいhotUpdateフックを使用しています。

PR内の検証では、モックプラグインで旧APIと新APIの動作を比較し、server.hot.sendの使用が必須であることを確認しています。一方で、後方互換性のためにserver.wsへのフォールバックも残されています。これにより、Vite 6.xから7.3.xまでの広範なバージョン範囲をサポートできます。

外部ファイルの判定ロジックでは、modules配列内のすべてのモジュールがtype === 'asset'またはid === undefinedの条件を満たすかをチェックしています。部分的なマッチではなく全数一致を要求することで、実際にViteで処理されているファイル(JSやCSSモジュール)を誤ってリロード対象にしないよう設計されています。

まとめ

この修正により、@sourceで監視される外部ファイルの変更が、Vite 7.1以降でも正しくフルページリロードをトリガーするようになりました。Environment APIへの移行に伴う破壊的変更に対応しつつ、旧バージョンとの互換性も維持した実装です。Tailwind CSS v4をViteで使用するプロジェクトにおいて、テンプレートファイル編集時の開発体験が復旧します。

記事メタデータ

Generated by:
Claude Sonnet 4.5 for DiffDaily

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文(総論)→背景・技術詳細・設計判断(各論)→まとめ(結論)という「総論→各論→結論」の3部構成が明確に適用されています。必須要素はすべて満たしており、任意要素である「設計判断」も含まれているため、読者の深い理解を助ける構成になっています。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きシンタックスハイライト(```言語:ファイルパス)およびGitHubのIssue/PRへのリンク記法([#123](URL))が、ガイドラインに沿って正しく使用されています。

対象読者への適合性 ✓ PASS

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

Vite、Tailwind CSS、HMRなどの専門用語が適切に使用されており、対象読者である専門知識を持つエンジニアに適した技術レベルと表現で書かれています。

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

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

各セクションが総論→各論の構成になっており、各段落はトピックセンテンスで始まっています。1段落1トピックの原則も守られ、段落長も適切であるため、非常に読みやすい文章構造です。

Diff内容との照合 ✓ PASS

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

記事内のコードブロックは、提供されたDiffの内容を正確に反映しています。`hotUpdate`フックの追加やテストコードの変更点など、重要な変更箇所が的確に抜粋・引用されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「Environment API」「hotUpdateフック」「モジュールグラフ」といった技術用語が、PR情報やViteの文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

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

Vite 7.1での変更が問題の原因であること、`hotUpdate`フックで`server.hot.send`を呼び出すことで解決することなど、技術的な説明はすべてPR情報とDiffのコードによって裏付けられており、論理的で正確です。

事実の突合 ✓ PASS

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

記事内のすべての主張は、PRのタイトル、Description、Diff内のコードやコメントに基づいており、根拠のない推測や憶測(ハルシネーション)は一切見られません。

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

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

PR番号(#19670)、Issue番号(#19637)、Viteのバージョン番号(7.1, 7.0.6など)といった数値や固有名詞は、すべてPR情報と正確に一致しています。

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

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

記事のタイトル「Vite 7.1以降で外部ファイル監視時のフルリロードを復旧」は、PRのタイトル「fix: restore full page reload for watched external files on Vite 7.1+」の内容を的確に要約しており、主題が完全に一致しています。

外部知識の正確性 ✓ PASS

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

記事で言及されているViteのバージョン間の挙動の違いは、Diff内のコメントやテストコードに基づいています。PR情報に記載のない外部知識(LTS、EOL情報など)の追加はなく、事実に基づいた記述が徹底されています。

時間表現の正確性 ✓ PASS

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

「Vite 7.0.6以前では」「Vite 7.1以降では」といった時間やバージョンに関する表現は、PRで示された問題の発生経緯と正確に一致しており、時間的な歪曲はありません。