2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

1人フロントエンドAdvent Calendar 2024

Day 18

Panda CSSで動作をカスタマイズする

Posted at

はじめに

Panda CSSChakra UIが手がける型安全なCSS in JSのツールです。

Panda CSSでスタイリングを行うときは、パッケージを直接使うのではなく、生成したファイルを参照して利用します。
Playgroundを見るとわかるように、@pandacss/devではなく、styled-systemを参照してスタイリングを行なっています。

この記事ではこのようには吐き出されるファイルに標準を超えて手を出したいときに利用できるhooksとそれをプラグインとして切り出す方法を紹介します。

hooks

hookはPanda CSSがファイルを生成する特定のライフサイクルで新たな動作と既存の動作の変更を追加するものです。

hookはPanda CSSの設定ファイルであるpanda.config.tsdefineConfigの中にhooksをキーとして配列で付与します。

指定可能なライフサイクルは10個あります(プライベートなものも合わせると11個です)。

config:resolved

config:resolvedpanda.config.tsが解決された後に呼ばれるhookです。hookの中で1番最初に呼び出されます。

config:resolvedを使って解決済みの設定に変更を加えます。

import { defineConfig } from '@pandacss/dev';
 
export default defineConfig({
  // ...
  hooks: {
    'config:resolved': ({ config, utils }) => {
      return utils.omit(config, ['eject']);
    },
  },
});

これによって、panda.config.tsで設定されたejectを削除した状態に設定が変わります。

tokens:created

tokenを生成するエンジンが生成されたときに呼ばれます。

tokens:createdを使ってCSS変数の名前やトークンの名前に対して共通の操作を行います。

import { defineConfig } from '@pandacss/dev';
 
export default defineConfig({
  hooks: {
    'tokens:created': ({ configure }) => {
      configure({
        formatTokenName: (path) => operation(path, 'token'),
        formatCssVar: (path, config) => ({
          var: operation(path, 'var', config.prefix),
          ref: operation(path, 'ref', config.prefix),
        }),
      });
    },
  },
});

utility:created

クラス名を生成するエンジンが生成されたときに呼ばれます。

utility:createdを使って生成するクラス名をハッシュ化する方法を指定します。

import { defineConfig } from '@pandacss/dev';
 
export default defineConfig({
  hooks: {
    'utility:created': ({ configure }) => {
      configure({
        toHash: (paths, toHash) => {
          return toHash(paths.join('-'));
        },
      }),
    },
  },
});

有無を言わさずハッシュ化するわけではなく、hashの設定がtrueの時のみ処理が走ります。

context:created

ファイルに書き出す内容を処理する準備が完了したタイミングで呼ばれます。

context:createdから一連の処理で利用するloggerを取り出します。

import { defineConfig } from '@pandacss/dev';
import { LoggerInterface } from '@pandacss/types';

let logger: LoggerInterface;
export default defineConfig({
  hooks: {
    'context:created': (context) => {
      logger = context.logger;
    },
  },
});

console.logではログが出ないことがあるので、これを用いてログ出力を行います。

config:change

panda.config.tsやPanda CSSを利用しているファイルに変更があったときに呼ばれます。

config:changeを用いて変更内容を確認します。

import { defineConfig } from '@pandacss/dev';
import { LoggerInterface } from '@pandacss/types';

let logger: LoggerInterface;
export default defineConfig({
  hooks: {
    'context:created': (context) => {
      logger = context.logger;
    },
    'config:change': (context) => {
      logger.debug(
        'plugin',
        message(contenxt.changes.diffs),
      );
    },
  },
});

どちらかといえばデバックで利用しやすいhookだと思っています。

parser:before

Panda CSSを利用しているファイルを解析する前に呼ばれます。

parser:beforeで解析の対象となるファイルを確認します。

import { defineConfig } from '@pandacss/dev';
import { LoggerInterface } from '@pandacss/types';

let logger: LoggerInterface;
export default defineConfig({
  hooks: {
    'context:created': (context) => {
      logger = context.logger;
    },
    'parser:before': (context) => {
      logger.debug(
        'plugin',
        context.filePath,
      );
    },
  },
});

大量のログが出るので、見つけたいファイルの種類が決まっている場合は絞り込むと良いです。

parser:after

Panda CSSを利用しているファイルを解析した後に呼ばれます。

parser:afterで解析の結果を確認します。

import { defineConfig } from '@pandacss/dev';
import { LoggerInterface } from '@pandacss/types';

let logger: LoggerInterface;
export default defineConfig({
  hooks: {
    'context:created': (context) => {
      logger = context.logger;
    },
    'parser:after': (context) => {
      logger.debug(
        'plugin',
        message(context.result),
      );
    },
  },
});

これもファイルごとに出力されるので、確認したいファイルの種類が決まっている場合は絞り込むと良いです。

codegen:prepare

codegenで生成した内容をファイルへ書き込む前に呼ばれます。

codegen:done

codegenで生成した内容をファイルへ書き込んだ後に呼ばれます。

cssgen:done

doneですが、最終的なCSSをファイルへ書き込む前に呼ばれます。

利用しないコードを削除して軽量化を促進します。

import { defineConfig } from '@pandacss/dev';

export default defineConfig({
  hooks: {
    'cssgen:done': ({ artifact, content }) => {
      if (artifact === 'styles.css') {
        return removeUnusedCss(content);
      }
    },
  },
});

プラグイン

作成したhookはプラグインとして共有できます。型をつけたい場合は@pandacss/typesを利用します。

import { PandaPlugin } from '@pandacss/types';

const examplePlugin: PandaPlugin = {
  name: 'example',
  hooks: {
    'config:change': configChangedHook,
  },
}

作成したプラグインはpanda.config.tsでインポートします。

panda.config.ts
import { defineConfig } from '@pandacss/dev';
 
export default defineConfig({
  plugins: [examplePlugin],
});

おわりに

Panda CSSで動作をカスタマイズする方法を紹介しました。
細かなライフサイクルごとにカスタマイズ可能なので、Panda CSS本体ではやってくれないが自分たちのワークスペースでは行ないたい何かを作りやすいです(パフォーマンスの悪さを感じた時の調査でも使えます)。このような自由度の高さはPanda CSSの特徴の1つだと思うので、気になった方はぜひPanda CSSを使ってみましょう。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?