Next.js x Panda CSS: Type-safeなCSS-in-JSで「クラス名地獄」に別れを告げる

Development tutorial - IT technology blog
Development tutorial - IT technology blog

なぜTailwindからPanda CSSに乗り換えるのか?

大規模なNext.jsプロジェクトでTailwind CSSを扱ったことがあるなら、延々と続くクラス名の羅列に「目が回る」ような感覚を覚えたことがあるはずです。時には1つの div に20〜30ものユーティリティクラスが詰め込まれ、HTMLコードが非常に読みにくくなることがあります。一方で、Styled-componentsやEmotionのような初期のCSS-in-JSライブラリは、メインスレッドに負荷をかけ、React Server Components (RSC) の仕組みと衝突しがちです。

そこで救世主として登場したのがPanda CSSです。Styled-componentsのようなオブジェクト形式でスタイルを記述でき、ビルド時に静的なCSSファイルを抽出します。実際に導入してみると、Pandaの補完機能(Intellisense)はTailwindよりも遥かに強力だと感じます。TypeScriptが即座にエラーを報告してくれるため、text-gray-500 と打つべきところを text-gry-500 と打ち間違える心配もありません。

Zero-runtimeメカニズム:高速化の秘密

Pandaは、アプリケーションの実行時にスタイルを計算するのではなく、静的解析(Static Analysis)の仕組みで動作します。ソースコード全体をスキャンしてスタイル関数を特定し、デプロイ前にそれらすべてを1つのCSSファイルにまとめます。

このアプローチには、主に3つの大きなメリットがあります。

  • Zero-runtime: ブラウザがCSSのためにJavaScriptを処理する時間を1ミリ秒も消費しません。ページの読み込み速度が大幅に向上します。
  • 絶対的なType-safety: 色から余白まで、すべてのトークンが厳密に定義されます。デザインシステムに存在しないカラーコードを使用しようとすると、コンパイルエラーになります。
  • RSCとの相性: スタイルが静的に抽出されるため、ファイルの先頭に "use client" を宣言することなく、Server Componentsで自由にPandaを使用できます。

Next.jsプロジェクトへの導入ステップ

App Routerを使用したNext.jsプロジェクトをゼロからセットアップしてみましょう。

ステップ1:プロジェクトの初期化

以下のコマンドを実行して、新しいプロジェクトを作成します。

npx create-next-app@latest my-panda-project --typescript --tailwind --eslint
cd my-panda-project

Pandaを使用する場合でも、初期段階でTailwindを残しておくと、比較したり既存のプラグインを活用したりするのに役立つことがあります。

ステップ2:Panda CSSのインストール

ライブラリをインストールし、設定ファイルを初期化します。

npm install -D @pandacss/dev
npx panda init

このコマンドの後、panda.config.ts ファイルが作成されます。これがテーマ、ブレイクポイント、ファイルスキャンのルールを定義する「司令塔」になります。

ステップ3:PostCSSの設定

postcss.config.mjs を開き、Pandaのプラグインを追加します。

export default {
  plugins: {
    '@pandacss/dev/postcss': {},
  },
};

ステップ4:コード生成の自動化

Pandaは型定義を保持するために styled-system ディレクトリを生成する必要があります。常に同期が取れるよう、package.json を更新しましょう。

{
  "scripts": {
    "prepare": "panda codegen",
    "dev": "next dev",
    "build": "panda codegen && next build"
  }
}

注意: styled-system ディレクトリには自動生成された多くのファイルが含まれます。リポジトリを整理しておくために、.gitignore に追加することをお勧めします。

スタイルの記述を開始する

クラス名の文字列を書く代わりに、直感的な css 関数を使用します。

import { css } from '../styled-system/css';

export default function Home() {
  return (
    <div className={css({ 
      fontSize: "2xl", 
      fontWeight: 'bold', 
      color: 'blue.600', 
      _hover: { color: 'red.500' } 
    })}>
      皆さんこんにちは、これはPanda CSSです!
    </div>
  );
}

_hover_dark といった構文は、Tailwindのプレフィックスよりもコードをすっきりと見せてくれます。複雑なデザインシステムを構築する際、私はよく ToolcraftのJSON Formatter を使って、設定に組み込む前にテーマオブジェクトをチェックし整形しています。これにより、手入力による構文エラーを効果的に防ぐことができます。

Recipesによる再利用

Recipesは、複数のバリエーション(variants)を持つコンポーネントを作成するためのPandaの機能です。

panda.config.ts での定義例:

recipes: {
  button: {
    className: 'button',
    base: { padding: '2', borderRadius: 'md' },
    variants: {
      visual: {
        solid: { bg: 'blue.500', color: 'white' },
        outline: { border: '1px solid', borderColor: 'blue.500' }
      }
    }
  }
}

使用時は、className={button({ visual: 'solid' })} と呼び出すだけです。非常にクリーンですね!

実践での経験則

いくつかの実際のプロジェクトを経て、3つの重要な教訓を得ました。

  1. Path Aliasの設定: tsconfig.json@/styled-system のエイリアスを設定しましょう。これにより、ディレクトリの深さを気にせずにどこからでもスタイルをインポートできるようになります。
  2. Bundle Sizeの管理: あまり使わないコンポーネントに対して複雑すぎるvariantsを多用しないようにしましょう。不要なスタイルの組み合わせを大量に生成すると、静的CSSファイルが肥大化する可能性があります。
  3. Shorthandの活用: 設定ファイルで marginTop の代わりに mt を使えるようにカスタマイズできます。これにより、Tailwindのようなスピード感でコードを書きつつ、型安全性を維持できます。

まとめ

Panda CSSは単なるツールではなく、UI管理における新しい思考法です。CSS-in-JSの柔軟性と静的CSSの圧倒的なパフォーマンスを両立させています。大規模なNext.jsプロジェクトを開始するなら、ぜひPandaをスタックに加えてみてください. 開発体験が劇的に向上すること間違いなしです!

セットアップで困ったことはありませんか?下のコメント欄でぜひ質問してください。一緒に解決しましょう!

Share: