はじめに
Panda CSSはChakra UIが手がける型安全なCSS in JSのツールです。
Panda CSSでスタイリングを行うときは、パッケージを直接使うのではなく、生成したファイルを参照して利用します。
Playgroundを見るとわかるように、@pandacss/dev
ではなく、styled-system
を参照してスタイリングを行なっています。
この記事ではこのようには吐き出されるファイルに標準を超えて手を出したいときに利用できるhooksとそれをプラグインとして切り出す方法を紹介します。
hooks
hook
はPanda CSSがファイルを生成する特定のライフサイクルで新たな動作と既存の動作の変更を追加するものです。
hook
はPanda CSSの設定ファイルであるpanda.config.ts
でdefineConfig
の中にhooks
をキーとして配列で付与します。
指定可能なライフサイクルは10個あります(プライベートなものも合わせると11個です)。
config:resolved
config:resolved
はpanda.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
でインポートします。
import { defineConfig } from '@pandacss/dev';
export default defineConfig({
plugins: [examplePlugin],
});
おわりに
Panda CSSで動作をカスタマイズする方法を紹介しました。
細かなライフサイクルごとにカスタマイズ可能なので、Panda CSS本体ではやってくれないが自分たちのワークスペースでは行ないたい何かを作りやすいです(パフォーマンスの悪さを感じた時の調査でも使えます)。このような自由度の高さはPanda CSSの特徴の1つだと思うので、気になった方はぜひPanda CSSを使ってみましょう。