addBase で @variant を使用可能に
addBase 内で @variant が利用できなかった点が意図せず残っていたため、プラグイン API がそれを補完できるよう拡張されました。今回の変更により、ベースレイヤーでもレスポンシブや状態ベースのバリアントを直接記述できるようになります。
背景
@variant が addBase で無視されていたのは、実装上の見落としとして 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 の呼び出し追加というシンプルな変更であり、既存の挙動を壊さない設計判断がなされています。