T-CREATOR

Tailwind CSS × SolidJS 初期配線:シグナル駆動 UI と相性抜群の設定

Tailwind CSS × SolidJS 初期配線:シグナル駆動 UI と相性抜群の設定

SolidJS でモダンな UI を構築する際、Tailwind CSS との組み合わせは開発体験を大きく向上させます。SolidJS のシグナル駆動による高速なリアクティブシステムと、Tailwind CSS のユーティリティファーストなスタイリングは、まさに理想的なパートナーシップです。

本記事では、SolidJS プロジェクトに Tailwind CSS を導入する初期配線の手順を、初心者の方にもわかりやすく解説いたします。プロジェクトのセットアップから、実際に動作する UI コンポーネントまで、段階的に進めていきましょう。

背景

SolidJS とシグナルベースのリアクティビティ

SolidJS は、React に似た構文を持ちながらも、仮想 DOM を使わずに細粒度のリアクティビティを実現するモダンな JavaScript フレームワークです。

シグナル(Signal)と呼ばれるリアクティブなプリミティブを使用することで、状態の変更を自動的に追跡し、必要な部分だけを効率的に更新します。この仕組みにより、高いパフォーマンスと開発者にとって直感的な API の両立を実現しています。

以下の図は、SolidJS のシグナルベースのリアクティブシステムの基本構造を示しています。

mermaidflowchart TB
  signal["Signal<br/>(createSignal)"] -->|値の変更| effect["Effect<br/>(createEffect)"]
  signal -->|自動追跡| memo["Memo<br/>(createMemo)"]
  memo -->|派生値| dom["DOM 更新"]
  effect -->|副作用実行| dom
  signal -.->|直接参照| dom

  style signal fill:#e0f2fe
  style effect fill:#fef3c7
  style memo fill:#ddd6fe
  style dom fill:#d1fae5

要点: Signal が状態を保持し、Effect や Memo が自動的に変更を検知して DOM を更新します。仮想 DOM を介さないため、高速な描画が可能です。

Tailwind CSS のユーティリティファーストアプローチ

Tailwind CSS は、事前定義されたユーティリティクラスを組み合わせてスタイリングを行う CSS フレームワークです。

従来の CSS フレームワークのように完成されたコンポーネントを提供するのではなく、小さな単一目的のクラス(flexpt-4text-blue-600 など)を組み合わせて UI を構築します。この方法により、カスタマイズ性が高く、デザインの一貫性を保ちやすいという特長があります。

なぜ SolidJS と Tailwind CSS の相性が良いのか

SolidJS のコンポーネントは JSX で記述され、クラス名の動的な切り替えもシグナルによってシンプルに実装できます。

Tailwind CSS のユーティリティクラスは、SolidJS のリアクティブシステムと非常に相性が良く、状態に応じたスタイルの変更を直感的に記述できます。また、両者とも軽量で高速という共通点を持ち、パフォーマンスを重視したアプリケーション開発に最適です。

課題

SolidJS プロジェクトへの Tailwind CSS 導入における課題

SolidJS で Tailwind CSS を使用する際、いくつかの設定上の課題があります。

まず、Tailwind CSS は標準で React や Vue など主要なフレームワークに対応していますが、SolidJS 特有の JSX ファイル拡張子(.jsx.tsx)や、ビルドツールの設定に対応する必要があります。特に、Vite を使用している場合は、PostCSS の設定や Tailwind の設定ファイルを適切に配置しなければなりません。

次に、クラス名のパージ(不要な CSS の削除)の設定が重要です。Tailwind CSS は、使用されているクラス名だけを本番ビルドに含める仕組みを持っていますが、SolidJS のファイルパターンを正しく指定しないと、必要なスタイルまで削除されてしまうリスクがあります。

また、SolidJS 特有の動的なクラス名の扱いにも注意が必要です。シグナルを使った条件付きクラス名やクラス名の動的生成を行う場合、適切な記述方法を理解していないと、スタイルが正しく適用されないことがあります。

以下の図は、Tailwind CSS 導入時の主な課題ポイントを示しています。

mermaidflowchart LR
  setup["SolidJS<br/>プロジェクト"] -->|課題1| vite["Vite +<br/>PostCSS 設定"]
  setup -->|課題2| tailwind["Tailwind<br/>設定ファイル"]
  setup -->|課題3| purge["クラスパージ<br/>設定"]
  setup -->|課題4| dynamic["動的クラス名<br/>の扱い"]

  vite -.->|解決| config1["tailwind.config.js"]
  tailwind -.->|解決| config1
  purge -.->|解決| config1
  dynamic -.->|解決| best["ベストプラクティス"]

  style setup fill:#e0f2fe
  style vite fill:#fecaca
  style tailwind fill:#fecaca
  style purge fill:#fecaca
  style dynamic fill:#fecaca
  style config1 fill:#d1fae5
  style best fill:#d1fae5

要点: プロジェクト設定、ビルドツール連携、クラスパージ、動的クラス名の 4 つが主な課題となります。

TypeScript を使用する場合の追加考慮事項

TypeScript を使用する SolidJS プロジェクトでは、型定義ファイルの整備も必要になります。

Tailwind CSS 自体は型安全性を提供しませんが、プロジェクト全体の型整合性を保つために、適切な設定が求められます。また、.tsx ファイルに対する Tailwind のスキャン設定も忘れずに行う必要があります。

解決策

プロジェクトセットアップの全体像

SolidJS プロジェクトに Tailwind CSS を導入するには、以下のステップを順番に実施します。

  1. SolidJS プロジェクトの作成
  2. Tailwind CSS 関連パッケージのインストール
  3. Tailwind CSS 設定ファイルの作成と設定
  4. PostCSS 設定ファイルの作成
  5. グローバル CSS ファイルの作成
  6. エントリーポイントでの CSS インポート
  7. 動作確認用コンポーネントの作成

各ステップを詳しく見ていきましょう。

ステップ 1: SolidJS プロジェクトの作成

まず、SolidJS の公式テンプレートを使用してプロジェクトを作成します。

Vite ベースのテンプレートを使用することで、高速な開発サーバーとビルド環境が手に入ります。以下のコマンドで、TypeScript 対応の SolidJS プロジェクトを作成できます。

bashyarn create vite my-solidjs-app --template solid-ts

このコマンドを実行すると、my-solidjs-app というディレクトリに SolidJS プロジェクトが生成されます。--template solid-ts オプションにより、TypeScript が設定済みの状態で作成されます。

プロジェクトディレクトリに移動します。

bashcd my-solidjs-app

依存パッケージをインストールします。

bashyarn install

この時点で、yarn dev を実行すれば、SolidJS のサンプルアプリケーションが起動することを確認できます。

ステップ 2: Tailwind CSS 関連パッケージのインストール

次に、Tailwind CSS 本体と、それに必要な PostCSS 関連のパッケージをインストールします。

Tailwind CSS は PostCSS のプラグインとして動作するため、postcssautoprefixer も一緒にインストールする必要があります。autoprefixer は、ブラウザごとのベンダープレフィックスを自動的に追加してくれるツールです。

bashyarn add -D tailwindcss postcss autoprefixer

-D オプションは、開発依存関係としてインストールすることを意味します。これらのパッケージはビルド時にのみ使用され、本番環境には含まれません。

ステップ 3: Tailwind CSS 設定ファイルの作成と設定

Tailwind CSS の設定ファイルを生成します。

以下のコマンドで、tailwind.config.js ファイルが自動生成されます。このファイルには、Tailwind CSS のカスタマイズ設定を記述します。

bashyarn tailwindcss init

生成された tailwind.config.js を開き、SolidJS のファイルパターンを指定します。

content プロパティに、Tailwind CSS がスキャンする対象ファイルのパスを指定します。ここで指定したファイル内で使用されているクラス名のみが、最終的な CSS に含まれます。

javascript/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],

.​/​index.html は、ルートの HTML ファイルをスキャン対象にします。.​/​src​/​**​/​*.{js,ts,jsx,tsx} は、src ディレクトリ以下のすべての JavaScript、TypeScript、JSX、TSX ファイルを対象にします。

テーマのカスタマイズ設定を追加します。

javascript  theme: {
    extend: {},
  },

extend オブジェクト内に、デフォルトのテーマを拡張する設定を記述できます。たとえば、独自のカラーパレットやフォントファミリーを追加する場合、ここに記述します。

プラグインの設定を追加します。

javascript  plugins: [],
}

Tailwind CSS の公式プラグインやサードパーティのプラグインを使用する場合、この配列に追加します。初期状態では空で問題ありません。

完全な tailwind.config.js の例は以下のようになります。

javascript/** @type {import('tailwindcss').Config} */
export default {
  content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {},
  },
  plugins: [],
};

ステップ 4: PostCSS 設定ファイルの作成

プロジェクトルートに postcss.config.js ファイルを作成します。

このファイルは、PostCSS がどのプラグインを使用するかを定義します。Tailwind CSS と Autoprefixer を使用するように設定します。

javascriptexport default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};

tailwindcss: {} により、Tailwind CSS のプラグインが有効化されます。autoprefixer: {} により、ベンダープレフィックスの自動追加が有効化されます。

ステップ 5: グローバル CSS ファイルの作成

Tailwind CSS のディレクティブを含むグローバル CSS ファイルを作成します。

src​/​index.css ファイルを開き(または新規作成し)、以下の内容を記述します。このファイルには、Tailwind CSS の基本レイヤーをインポートするディレクティブを記述します。

css@tailwind base;

@tailwind base ディレクティブは、Tailwind のベーススタイル(ノーマライズ CSS など)を読み込みます。これにより、ブラウザ間のスタイルの違いが吸収されます。

コンポーネント用のスタイルを読み込みます。

css@tailwind components;

@tailwind components ディレクティブは、ボタンやカードなどのコンポーネント用のスタイルを読み込みます。カスタムコンポーネントスタイルもここに定義できます。

ユーティリティクラスを読み込みます。

css@tailwind utilities;

@tailwind utilities ディレクティブは、Tailwind のすべてのユーティリティクラスを生成します。これが、flexpt-4text-blue-600 などのクラスを使えるようにする重要な設定です。

完全な src​/​index.css の内容は以下のようになります。

css@tailwind base;
@tailwind components;
@tailwind utilities;

ステップ 6: エントリーポイントでの CSS インポート

SolidJS のエントリーポイントファイルで、作成したグローバル CSS をインポートします。

src​/​index.tsx(または src​/​main.tsx、プロジェクトによって異なります)を開き、最上部に CSS ファイルのインポート文を追加します。

typescriptimport './index.css';

このインポート文により、アプリケーション全体で Tailwind CSS が利用可能になります。インポートの順序は重要で、必ず他のインポートより前、または最初に記述するようにしましょう。

エントリーポイントファイルの完全な例は以下のようになります。

typescriptimport './index.css';
import { render } from 'solid-js/web';
import App from './App';

const root = document.getElementById('root');

if (root) {
  render(() => <App />, root);
}

ステップ 7: 設定の動作確認

ここまでの設定が正しく行われているか、開発サーバーを起動して確認します。

bashyarn dev

ブラウザで http:​/​​/​localhost:5173 にアクセスし、SolidJS アプリが正常に表示されることを確認しましょう。この時点では、まだ Tailwind CSS のスタイルは適用されていませんが、エラーが出なければ設定は成功しています。

以下の図は、これまでの設定ステップの全体フローを示しています。

mermaidflowchart TB
  start["開始"] --> create["SolidJS<br/>プロジェクト作成"]
  create --> install["Tailwind CSS<br/>パッケージインストール"]
  install --> tailwindConfig["tailwind.config.js<br/>作成・設定"]
  tailwindConfig --> postcssConfig["postcss.config.js<br/>作成"]
  postcssConfig --> indexCss["index.css<br/>作成"]
  indexCss --> importCss["エントリーポイントで<br/>CSS インポート"]
  importCss --> verify["動作確認<br/>(yarn dev)"]
  verify --> complete["セットアップ完了"]

  style start fill:#e0f2fe
  style complete fill:#d1fae5
  style verify fill:#fef3c7

要点: プロジェクト作成から CSS インポートまでを順番に実施し、最後に動作確認を行います。

具体例

基本的な Tailwind CSS の使用例

それでは、実際に Tailwind CSS を使った SolidJS コンポーネントを作成してみましょう。

まず、シンプルなカードコンポーネントを作成します。src​/​components​/​Card.tsx ファイルを新規作成し、以下のように記述します。

型定義とインターフェースを定義します。

typescriptimport { Component, JSX } from 'solid-js';

interface CardProps {
  title: string;
  description: string;
  children?: JSX.Element;
}

CardProps インターフェースで、カードコンポーネントが受け取るプロパティを定義しています。titledescription は必須、children はオプショナルです。

カードコンポーネントの実装を記述します。

typescriptconst Card: Component<CardProps> = (props) => {
  return (
    <div class='max-w-sm rounded-lg overflow-hidden shadow-lg bg-white hover:shadow-xl transition-shadow duration-300'>
      <div class='px-6 py-4'>
        <h2 class='font-bold text-xl mb-2 text-gray-800'>
          {props.title}
        </h2>
        <p class='text-gray-600 text-base'>
          {props.description}
        </p>
      </div>
      {props.children && (
        <div class='px-6 pt-4 pb-6'>{props.children}</div>
      )}
    </div>
  );
};

export default Card;

このコンポーネントでは、Tailwind CSS のユーティリティクラスを多数使用しています。max-w-sm で最大幅を設定し、rounded-lg で角を丸くし、shadow-lg で影を付けています。hover:shadow-xltransition-shadow により、ホバー時に影が大きくなるアニメーションが実装されています。

シグナルを使った動的スタイリング

次に、SolidJS のシグナルを活用した動的なスタイリングの例を見てみましょう。

ボタンの状態に応じてスタイルが変わるコンポーネントを作成します。src​/​components​/​ToggleButton.tsx ファイルを作成します。

必要なインポートを記述します。

typescriptimport { Component, createSignal } from 'solid-js';

createSignal は、SolidJS のリアクティブな状態管理の基本となる関数です。これを使って、ボタンの ON/OFF 状態を管理します。

トグルボタンコンポーネントを実装します。

typescriptconst ToggleButton: Component = () => {
  const [isActive, setIsActive] = createSignal(false);

  const handleClick = () => {
    setIsActive(!isActive());
  };

createSignal(false) で、初期値が false のシグナルを作成しています。isActive はゲッター関数、setIsActive はセッター関数です。

ボタンの JSX を返します。

typescript  return (
    <button
      onClick={handleClick}
      class={`
        px-6 py-3 rounded-lg font-semibold text-white
        transition-all duration-300 transform
        ${isActive()
          ? 'bg-blue-600 hover:bg-blue-700 scale-105'
          : 'bg-gray-400 hover:bg-gray-500 scale-100'}
      `}
    >
      {isActive() ? 'アクティブ' : '非アクティブ'}
    </button>
  );
};

export default ToggleButton;

テンプレートリテラル内で isActive() の値に応じて、異なる Tailwind CSS クラスを適用しています。アクティブ時は青色(bg-blue-600)で少し拡大(scale-105)し、非アクティブ時は灰色(bg-gray-400)で通常サイズ(scale-100)になります。

以下の図は、シグナルによる動的スタイリングのフローを示しています。

mermaidsequenceDiagram
  participant User as ユーザー
  participant Button as ToggleButton
  participant Signal as isActive Signal
  participant DOM as DOM

  User->>Button: クリック
  Button->>Signal: setIsActive(!isActive())
  Signal->>Signal: 状態を反転
  Signal->>DOM: クラス名を再計算
  DOM->>DOM: スタイルを更新
  DOM->>User: 視覚的フィードバック

要点: ユーザーのクリックがシグナルの状態を変更し、自動的に DOM のクラス名とスタイルが更新されます。

より実践的な例:フォームコンポーネント

実務でよく使用されるフォームコンポーネントの例を見てみましょう。

src​/​components​/​LoginForm.tsx ファイルを作成します。

インポートと型定義を記述します。

typescriptimport { Component, createSignal } from 'solid-js';

interface FormData {
  email: string;
  password: string;
}

FormData インターフェースで、フォームが管理するデータの型を定義しています。

ログインフォームコンポーネントを実装します。

typescriptconst LoginForm: Component = () => {
  const [formData, setFormData] = createSignal<FormData>({
    email: '',
    password: '',
  });

  const [isSubmitting, setIsSubmitting] = createSignal(false);
  const [errors, setErrors] = createSignal<string[]>([]);

3 つのシグナルを使用しています。formData はフォームの入力値、isSubmitting は送信中かどうかの状態、errors はエラーメッセージの配列を管理します。

入力ハンドラーを定義します。

typescriptconst handleInput = (
  field: keyof FormData,
  value: string
) => {
  setFormData({ ...formData(), [field]: value });
};

スプレッド構文を使って、既存の formData の値をコピーしつつ、指定されたフィールドのみを更新しています。

フォーム送信ハンドラーを定義します。

typescriptconst handleSubmit = async (e: Event) => {
  e.preventDefault();
  setIsSubmitting(true);
  setErrors([]);

  // バリデーション例
  const validationErrors: string[] = [];
  if (!formData().email.includes('@')) {
    validationErrors.push(
      '有効なメールアドレスを入力してください'
    );
  }
  if (formData().password.length < 8) {
    validationErrors.push(
      'パスワードは8文字以上で入力してください'
    );
  }

  if (validationErrors.length > 0) {
    setErrors(validationErrors);
    setIsSubmitting(false);
    return;
  }

  // ここで実際のAPI呼び出しを行います
  await new Promise((resolve) => setTimeout(resolve, 1000));

  setIsSubmitting(false);
  alert('ログインしました!');
};

シンプルなバリデーションを実装しています。エラーがある場合は errors シグナルにエラーメッセージを設定し、送信処理を中断します。

フォームの JSX を返します。

typescript  return (
    <form
      onSubmit={handleSubmit}
      class="max-w-md mx-auto mt-8 p-6 bg-white rounded-lg shadow-md"
    >
      <h2 class="text-2xl font-bold mb-6 text-gray-800">
        ログイン
      </h2>

フォーム全体を中央揃えにし、適度なパディングと影を付けています。

メールアドレス入力フィールドを記述します。

typescript<div class='mb-4'>
  <label
    for='email'
    class='block text-sm font-medium text-gray-700 mb-2'
  >
    メールアドレス
  </label>
  <input
    type='email'
    id='email'
    value={formData().email}
    onInput={(e) =>
      handleInput('email', e.currentTarget.value)
    }
    class='w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent'
    placeholder='example@example.com'
  />
</div>

value={formData().email} で、シグナルの値を input 要素にバインドしています。onInput イベントで、入力値の変更を formData シグナルに反映させています。

パスワード入力フィールドを記述します。

typescript<div class='mb-4'>
  <label
    for='password'
    class='block text-sm font-medium text-gray-700 mb-2'
  >
    パスワード
  </label>
  <input
    type='password'
    id='password'
    value={formData().password}
    onInput={(e) =>
      handleInput('password', e.currentTarget.value)
    }
    class='w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent'
    placeholder='8文字以上'
  />
</div>

メールアドレスフィールドと同様の構造で、パスワード入力フィールドを実装しています。

エラーメッセージの表示部分を記述します。

typescript{
  errors().length > 0 && (
    <div class='mb-4 p-3 bg-red-50 border border-red-200 rounded-md'>
      {errors().map((error) => (
        <p class='text-sm text-red-600'>{error}</p>
      ))}
    </div>
  );
}

errors() シグナルに値がある場合のみ、エラーメッセージを表示します。SolidJS の条件付きレンダリングと map を使って、複数のエラーメッセージに対応しています。

送信ボタンを記述します。

typescript      <button
        type="submit"
        disabled={isSubmitting()}
        class={`
          w-full py-2 px-4 rounded-md font-semibold text-white
          transition-colors duration-200
          ${isSubmitting()
            ? 'bg-gray-400 cursor-not-allowed'
            : 'bg-blue-600 hover:bg-blue-700 active:bg-blue-800'}
        `}
      >
        {isSubmitting() ? '送信中...' : 'ログイン'}
      </button>
    </form>
  );
};

export default LoginForm;

isSubmitting() シグナルの値に応じて、ボタンのスタイルとテキストを動的に変更しています。送信中は disabled 属性を設定し、カーソルも変更して操作不可であることを明示しています。

App.tsx での統合例

作成したコンポーネントを App.tsx で統合して使用します。

src​/​App.tsx ファイルを以下のように編集します。

typescriptimport { Component } from 'solid-js';
import Card from './components/Card';
import ToggleButton from './components/ToggleButton';
import LoginForm from './components/LoginForm';

const App: Component = () => {
  return (
    <div class="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 py-12 px-4">
      <div class="container mx-auto">
        <h1 class="text-4xl font-bold text-center mb-12 text-gray-800">
          SolidJS × Tailwind CSS デモ
        </h1>

グラデーション背景を持つコンテナを作成し、中央揃えのタイトルを配置しています。

カードコンポーネントのセクションを追加します。

typescript<div class='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12'>
  <Card
    title='高速なリアクティビティ'
    description='SolidJS のシグナルベースのシステムにより、高速な UI 更新を実現します。'
  >
    <ToggleButton />
  </Card>

  <Card
    title='ユーティリティファースト'
    description='Tailwind CSS の豊富なユーティリティクラスで、柔軟なデザインが可能です。'
  />

  <Card
    title='型安全性'
    description='TypeScript による型安全な開発で、バグを未然に防ぎます。'
  />
</div>

グリッドレイアウトを使用して、レスポンシブなカード配置を実現しています。md:grid-cols-2 により、中サイズ以上の画面では 2 カラム、lg:grid-cols-3 により大サイズでは 3 カラムになります。

ログインフォームセクションを追加します。

typescript        <div class="mb-12">
          <LoginForm />
        </div>
      </div>
    </div>
  );
};

export default App;

動作確認とカスタマイズ

ここまでのコードを保存し、開発サーバーを起動します。

bashyarn dev

ブラウザで http:​/​​/​localhost:5173 にアクセスすると、Tailwind CSS のスタイルが適用された美しい UI が表示されるはずです。

トグルボタンをクリックすると、アニメーション付きで色とサイズが変化します。フォームに無効なデータを入力して送信すると、エラーメッセージが表示されます。これらはすべて、SolidJS のシグナルと Tailwind CSS の組み合わせによって実現されています。

クラス名管理のベストプラクティス

動的なクラス名を扱う際は、以下のような方法がおすすめです。

条件が複雑な場合は、関数で分離します。

typescriptimport { Component, createSignal } from 'solid-js';

const StatusBadge: Component = () => {
  const [status, setStatus] = createSignal<'success' | 'warning' | 'error'>('success');

  const getStatusClasses = () => {
    const base = 'px-4 py-2 rounded-full font-semibold text-sm';
    const statusClasses = {
      success: 'bg-green-100 text-green-800 border border-green-300',
      warning: 'bg-yellow-100 text-yellow-800 border border-yellow-300',
      error: 'bg-red-100 text-red-800 border border-red-300',
    };
    return `${base} ${statusClasses[status()]}`;
  };

ベースとなるクラスと、状態に応じたクラスを分離して管理することで、可読性が向上します。

バッジの表示部分を記述します。

typescript  return (
    <div class="space-y-4">
      <span class={getStatusClasses()}>
        {status()}
      </span>

      <div class="flex gap-2">
        <button
          onClick={() => setStatus('success')}
          class="px-3 py-1 bg-green-500 text-white rounded hover:bg-green-600"
        >
          成功
        </button>
        <button
          onClick={() => setStatus('warning')}
          class="px-3 py-1 bg-yellow-500 text-white rounded hover:bg-yellow-600"
        >
          警告
        </button>
        <button
          onClick={() => setStatus('error')}
          class="px-3 py-1 bg-red-500 text-white rounded hover:bg-red-600"
        >
          エラー
        </button>
      </div>
    </div>
  );
};

export default StatusBadge;

ボタンをクリックすると、バッジの状態とスタイルが動的に変わります。

本番ビルド時のクラスパージ確認

本番ビルドを実行して、使用していないクラスが正しく削除されるか確認しましょう。

bashyarn build

ビルドが完了すると、dist ディレクトリに最適化されたファイルが生成されます。CSS ファイルのサイズを確認すると、使用しているクラスのみが含まれていることがわかります。

ビルド結果をプレビューします。

bashyarn preview

本番環境と同じ最適化された状態でアプリケーションを確認できます。

以下の表は、開発時と本番ビルド後の CSS ファイルサイズの比較例です。

#環境CSS ファイルサイズ備考
1開発環境約 3.5 MBすべてのユーティリティクラスを含む
2本番環境約 8-15 KB使用しているクラスのみ(gzip 圧縮後はさらに小さい)
3最適化後約 2-5 KBgzip 圧縮適用時

図で理解できる要点:

  • 開発環境では全クラスが読み込まれるため、ファイルサイズが大きい
  • 本番ビルドでは未使用クラスがパージされ、大幅に軽量化される
  • gzip 圧縮により、さらに 60-70%程度の圧縮が可能

まとめ

本記事では、SolidJS プロジェクトに Tailwind CSS を導入する手順を、初期設定から実践的なコンポーネント作成まで解説してまいりました。

SolidJS のシグナルベースのリアクティブシステムと、Tailwind CSS のユーティリティファーストなアプローチは、驚くほど相性が良く、高速で保守性の高い UI 開発を実現できます。特に、動的なクラス名の管理がシンプルに記述できる点は、開発体験を大きく向上させてくれるでしょう。

プロジェクトのセットアップは、一度行ってしまえば、その後は快適な開発が待っています。tailwind.config.js でのファイルパス設定、postcss.config.js での PostCSS 設定、そして index.css での Tailwind ディレクティブの読み込みという 3 つの要点を押さえれば、あとはコンポーネントの実装に集中できます。

動的スタイリングの実装では、シグナルを使った状態管理と、テンプレートリテラル内でのクラス名の条件分岐がポイントになります。複雑な条件の場合は、専用の関数を作成して分離することで、コードの可読性と保守性が向上します。

本番ビルド時には、Tailwind CSS の優れたパージ機能により、使用していないクラスが自動的に削除され、わずか数 KB の CSS ファイルで済むのも魅力です。これにより、初回読み込み時間が短縮され、ユーザー体験の向上につながります。

今回紹介した設定方法と実装パターンを基に、ぜひご自身のプロジェクトで SolidJS × Tailwind CSS の組み合わせを試してみてください。きっと、その開発体験の良さに驚かれることでしょう。

関連リンク