`@variant` が JS プラグイン API でも利用可能に

tailwindlabs/tailwindcss

この PR は、JavaScript ベースのプラグイン API 内で @variant を利用できるようにする回帰テストを追加し、コアロジックを修正して @variant の置換処理を正しく実行すると同時に、AST の走査を二重に行う無駄を排除しました。

背景

Tailwind CSS v4.3.1 で導入された addBase プラグイン API 向けの @variant 対応は、カスタムバリアントが後から追加された場合に早すぎる置換が原因でエラーになるという回帰を引き起こしました。結果として、@variant が CSS 出力に残るか、ビルドが失敗するケースが報告されました。

この問題は PR #20247 によって addBase での置換タイミングが遅延されて修正されたものの、同様の置換ロジックが JavaScript プラグイン API(例: @tailwindcss/typography)でも使用されているため、同様のバグが潜在的に残っていました。

結論として、JS ベースのプラグインでも @variant が安全に使用できることを保証し、将来的な回帰を防ぐ必要がありました。

技術的な変更

テスト側では、@tailwindcss/typography プラグインとカスタムバリアントを組み合わせたシナリオを統合テストとして追加し、ビルド結果に @variant が残らないことを検証します。これにより、実際の利用環境での回帰が自動的に捕捉できるようになります。

test(
  'builds the `@tailwindcss/typography` plugin utilities with `@variant` usages',
  {
    fs: {
      'package.json': json`
        {
          "dependencies": {
            "@tailwindcss/typography": "^0.5.14",
            "tailwindcss": "workspace:^",
            "@tailwindcss/cli": "workspace:^"
          }
        }
      `,
      'src/index.css': css`
        @import 'tailwindcss/utilities';
        @theme { --breakpoint-sm: 640px; }
        @plugin '@tailwindcss/typography';
        @custom-variant custom (&.custom);
      `,
      'tailwind.config.js': ts`
        module.exports = {
          theme: {
            typography: ({ theme }) => ({
              custom: {
                css: {
                  hr: {
                    '--x': '1',
                    '@variant sm:custom': { '--x': '2' },
                  },
                },
              },
            }),
          },
        };
      `,
    },
  }
);

このテストは、@variant sm:custom が最終的な CSS に現れないことを期待し、ビルドが成功するかどうかを検証します。テストファイルは既存のテストスイートに統合され、CI で自動的に実行されます。

コアロジックでは、buildDesignSystem 関数内で AST のノード配列を一度だけ生成し、substituteFunctionssubstituteAtVariant の両方に同じ配列を渡すように変更しました。これにより、同一ノード集合を二度走査するオーバーヘッドが除去されます。

@@
-        substituteFunctions(
-          ast.map(({ node }) => node),
-          designSystem,
-        )
-        substituteAtVariant(
-          ast.map(({ node }) => node),
-          designSystem,
-        )
+        let nodes = ast.map((value) => value.node)
+        substituteFunctions(nodes, designSystem)
+        substituteAtVariant(nodes, designSystem)

nodes 変数は ast から抽出した node のみを保持し、以降の置換処理はこの配列に対して行われます。コード量は減少し、意図が明確になると同時に、実行時のメモリ割り当て回数も削減されます。

結論として、テスト追加とコア修正により、JS プラグイン API でも @variant が正しく処理され、ビルド速度の微小な改善も期待できます。

設計判断

今回の実装は、substituteAtVariant を既存の substituteFunctions と同一ノードリストに対して実行するというシンプルな統合戦略を採用しました。ロジックの分割は維持しつつ、共通データ構造を共有することで余分な計算を排除しています。

このアプローチは、コードベースの可読性を保ちつつ、将来的に他の置換処理が追加された場合でも同様にノードリストを再利用できる拡張性を提供します。パフォーマンス向上は限定的ですが、無駄なループを除去したことでメンテナンスコストが低減しました。

結論として、最小限の変更で後方互換性を確保し、@variant の使用範囲を拡大した設計判断は、Tailwind CSS の拡張性と安定性を同時に高める選択と言えます。

まとめ

本 PR は、JavaScript ベースのプラグイン API でも @variant が安全に利用できるように統合テストを導入し、コアの置換ロジックを最適化しました。テスト追加により回帰が防止され、AST の二重走査削減で僅かなビルド効率向上が期待できます。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
9e0b8d86

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

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

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

リード文があり、背景・技術的変更・設計判断・まとめのセクションが揃っており、総論→各論→結論の流れが明確です。

カスタムMarkdown構文 ⚠ WARNING

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

コードブロックは `言語:ファイルパス` 形式で正しく記述されていますが、PR へのリンクが `[PR #20252](URL)` となっており、仕様の `[ #123 ](URL)` 形式から外れています。

対象読者への適合性 ✓ PASS

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

内容は Tailwind CSS の内部実装や AST 操作に関する専門的な記述で、エンジニア向けに適切です。

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

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

各セクションは総論パラグラフ→各論パラグラフ→結論パラグラフの構成になり、段落はトピックセンテンスで始まり、長さも適切です。

Diff内容との照合 ⚠ WARNING

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

`design-system.ts` の変更は Diff と完全に一致していますが、`plugins.test.ts` のテスト追加部分で `index.html` や `@config` 行が省略されています。省略は情報の欠落につながるため警告としました。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

AST、`@variant`、`substituteFunctions` などの用語は PR と一致しており、誤用はありません。

説明の技術的正確性 ✓ PASS

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

AST 二重走査の削減やテストによる回帰防止の説明は PR の記述と整合しており、技術的に正確です。

事実の突合 ✓ PASS

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

記事内の主張はすべて PR のタイトル・説明・Diff に裏付けられており、捏造や推測はありません。

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

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

PR 番号 (#20252, #20247) は正しく記載されており、他の数値・固有名詞の誤りは見当たりません。

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

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

記事タイトルは PR タイトル「Ensure `@variant` can be used in JS based APIs」の意味を日本語で正確に表現しています。

外部知識の正確性 ✓ PASS

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

バージョンサポート状況やリリース予定など、PR に記載されていない外部情報は含まれていません。

時間表現の正確性 ✓ PASS

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

時間表現は PR の記述と矛盾せず、正確です。