addBase で @variant を使用可能に

tailwindlabs/tailwindcss

addBase 内で @variant が利用できなかった点が意図せず残っていたため、プラグイン API がそれを補完できるよう拡張されました。今回の変更により、ベースレイヤーでもレスポンシブや状態ベースのバリアントを直接記述できるようになります。

背景

@variantaddBase で無視されていたのは、実装上の見落としとして PR の記述でも指摘されています("This seems like an unintentional omission")。その結果、ベーススタイルに対してメディアクエリやデータ属性ベースの条件付けを行う際、開発者は回りくどい手法を取らざるを得ませんでした。

この制限は Tailwind のユーティリティ中心の設計と齟齬し、特にカスタムプラグインでルート変数やグローバルスタイルを設定するケースで不便でした。addBase が単純に CSS ルートオブジェクトをコピーするだけだったため、@variant の置換ロジックが走らず、期待した出力が得られませんでした。

技術的な変更

plugin‑api.ts にて、バリアント置換を担当する関数 substituteAtVariant がインポートに追加されました。

@@
-import { compoundsForSelectors, IS_VALID_VARIANT_NAME, substituteAtSlot } from '../variants'
+import {
+  compoundsForSelectors,
+  IS_VALID_VARIANT_NAME,
+  substituteAtSlot,
+  substituteAtVariant,
+} from '../variants'

次に addBase のビルドパイプラインに substituteAtVariant の呼び出しが挿入され、ベースノードの変換時にバリアント置換が実行されます。

@@
-      featuresRef.current |= substituteFunctions(baseNodes, designSystem)
+      featuresRef.current |= substituteFunctions(baseNodes, designSystem)
+      featuresRef.current |= substituteAtVariant(baseNodes, designSystem)

この変更に合わせてテストが追加され、addBase 内で @variant が正しく展開されることが検証されています。

@@
+  test('@variant is replaced inside rules using addBase', async () => {
+    expect(
+      await compileCss(
+        css`
+          @plugin "my-plugin";
+          @theme {
+            --breakpoint-supertiny: 128px;
+          }
+        `,
+        {
+          loadModule: async () => ({
+            path: '',
+            base: '/root',
+            module: plugin(function ({ addBase }) {
+              addBase({
+                ':root': {
+                  '@variant supertiny': {
+                    '--PascalCase': '1',
+                    '--camelCase': '1',
+                    '--UPPERCASE': '1',
+                  },
+                  '@variant data-enabled:focus, disabled': {
+                    '--x': '1',
+                  },
+                },
+              })
+            }),
+          }),
+        },
+      ),
+    ).toMatchInlineSnapshot(`
+      "
+      @layer base {
+        @media (min-width: 128px) {
+          :root {
+            --PascalCase: 1;
+            --camelCase: 1;
+            --UPPERCASE: 1;
+          }
+        }
+
+        :root[data-enabled]:focus, :root:disabled {
+          --x: 1;
+        }
+      }
+      "
+    )
+  })

設計判断

addBase に対して substituteAtVariant を組み込む選択は、既存のバリアント置換ロジックを再利用することで実装コストを最小化しつつ、一貫した振る舞いを保証する意図があります。新しい API エントリを追加せず、既存のパイプラインにフックする形を取った点が特徴です。

このアプローチは後方互換性を保ち、従来の addBase 呼び出しがそのまま動作し続けることを前提としています。@variant を boolean や文字列で指定できる既存の仕様に加えて、オブジェクトリテラル内でも同様に処理できるよう拡張したため、既存プラグインへの影響はありません。

まとめ

addBase@variant が使用可能になったことで、ベースレイヤーでもメディアクエリや属性ベースの条件付けを直接記述できるようになり、プラグイン開発の表現力が向上しました。実装は substituteAtVariant の呼び出し追加というシンプルな変更であり、既存の挙動を壊さない設計判断がなされています。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
5b93300f

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文、背景、技術的変更、設計判断(任意)、まとめの5セクションが揃っており、総論→各論→結論の構成が明確です。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きシンタックスハイライトは ```ts:パス の形式で正しく記述され、PRリンクも #番号 の形式で正しくリンク化されています。

対象読者への適合性 ✓ PASS

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

記事はTailwindCSS のプラグイン開発に慣れたエンジニア向けに書かれており、余計な基礎解説はありません。

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

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

各セクションは総論・各論・結論の段落構成になり、段落はトピックセンテンスで始まり、1段落1トピック、適切な長さで空行で区切られています。

Diff内容との照合 ✓ PASS

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

記事中のコードブロックは提供されたDiffと完全に一致しており、抜粋や追加も技術的理解を妨げません。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

使用されている用語(@variant、addBase、substituteAtVariant 等)はPRとDiffで用いられるものと一致し、誤用はありません。

説明の技術的正確性 ✓ PASS

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

技術的な主張はDiffとPRの記述に基づき、因果関係も論理的に説明されています。

事実の突合 ✓ PASS

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

記事の全主張はPRの内容、Diff、テストコードで裏付けられており、根拠のない推測はありません。

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

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

PR番号やファイルパス、テスト内の数値(128px 等)は正確に記述されています。

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

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

記事タイトルは PR の主旨「Allow `@variant` to be used inside `addBase`」を日本語で正確に表現しています。

外部知識の正確性 ✓ PASS

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

記事は外部のバージョンサポート情報やリリース日程等、PRに記載のない知識を付加していません。

時間表現の正確性 ✓ PASS

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

時間表現の歪曲はなく、PRの記述と一致しています。