T-CREATOR

Emotion × Vite の最短構築:開発高速化とソースマップ最適設定

Emotion × Vite の最短構築:開発高速化とソースマップ最適設定

React でスタイリングを行う際、CSS-in-JS ライブラリの Emotion は非常に人気があります。一方で、ビルドツールとして Vite が注目を集めています。この記事では、Emotion と Vite を組み合わせた環境を最短で構築し、開発を高速化するための設定、そしてデバッグ効率を最大化するソースマップの最適設定について詳しく解説します。

初めて Emotion と Vite を組み合わせる方でも、この記事を読めばすぐに開発を始められます。実際のコード例と設定ファイルを段階的に示しながら、つまずきやすいポイントも丁寧に説明していきますね。

背景

Emotion が選ばれる理由

Emotion は React アプリケーションで広く使われている CSS-in-JS ライブラリです。コンポーネントにスタイルを直接記述でき、TypeScript との相性も抜群ですね。動的なスタイリングやテーマ切り替えも簡単に実装できます。

従来の CSS ファイルと比較して、スタイルの再利用性が高く、コンポーネント単位での管理が可能になるため、大規模なアプリケーション開発でも保守性を保てます。

Vite の登場と普及

Vite は次世代のフロントエンドビルドツールとして、開発体験を劇的に向上させました。ES Modules を活用した超高速な開発サーバー起動、そして HMR(Hot Module Replacement)による瞬時の画面反映が特徴です。

従来の Webpack ベースの環境と比較すると、開発サーバーの起動時間が数十秒から数秒へと短縮されるケースも珍しくありません。

なぜ Emotion × Vite なのか

以下の図は、Emotion と Vite を組み合わせることで得られる開発フローの全体像を示しています。

mermaidflowchart TB
  dev["開発者"] -->|コード編集| vite["Vite 開発サーバー"]
  vite -->|超高速 HMR| emotion["Emotion 変換"]
  emotion -->|CSS 生成| browser["ブラウザ"]
  browser -->|即座に反映| dev

  vite -->|ESM ベース| fast["高速起動<br/>数秒"]
  emotion -->|CSS-in-JS| dynamic["動的スタイル<br/>型安全"]

図のポイント

  • Vite の高速な開発サーバーと Emotion の柔軟なスタイリングが相乗効果を発揮します
  • HMR により、スタイル変更が瞬時にブラウザに反映されます
  • 型安全な開発環境を実現できます

この組み合わせにより、従来の開発環境では実現できなかった「書いたらすぐ見える」体験が得られるのです。

課題

Emotion 導入時の設定の複雑さ

Emotion を Vite 環境で利用する際、いくつかの課題に直面することがあります。特に、@emotion​/​react の JSX Pragma 設定や、@emotion​/​babel-plugin の適用方法が分かりにくいという声が多く聞かれます。

Webpack 環境では Babel の設定が標準的でしたが、Vite では異なるアプローチが必要になりますね。

ソースマップの問題

開発中にスタイルのデバッグを行う際、ソースマップが正しく設定されていないと、ブラウザの開発者ツールで元のコードの位置が特定できません。

以下のような問題が発生します:

#問題影響
1ソースマップが生成されないデバッグ時に元のコード位置が分からない
2ソースマップの精度が低い行番号がずれる
3本番ビルドでソースマップが残るセキュリティリスク

エラーコード例

arduinoError: Cannot find source map for emotion styles
TypeError: Unable to resolve original source position

これらのエラーは、Vite の設定と Emotion のトランスパイル設定が適切に連携していない場合に発生します。

パフォーマンス最適化の難しさ

Emotion のランタイムコストと Vite のビルド最適化をバランスよく設定する必要があります。不適切な設定では、開発時は快適でも本番環境でパフォーマンスが低下するケースがあります。

以下の図は、設定が不適切な場合の問題フローを示しています。

mermaidflowchart LR
  dev_env["開発環境"] -->|不適切な設定| build["ビルド"]
  build -->|最適化なし| bundle["肥大化したバンドル"]
  bundle -->|配信| prod["本番環境"]
  prod -->|遅い| user["ユーザー体験低下"]

  dev_env -.->|ソースマップ設定ミス| debug["デバッグ困難"]

図で理解できる要点

  • 開発環境と本番環境で異なる設定が必要
  • ソースマップの設定ミスがデバッグ効率を大きく下げる
  • バンドルサイズの最適化が重要

解決策

最短構築手順

Emotion × Vite 環境を最短で構築する手順を、段階的に解説します。

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

まず、Vite で React プロジェクトを作成します。Yarn を使用して進めていきましょう。

bash# Vite + React + TypeScript プロジェクトを作成
yarn create vite my-emotion-app --template react-ts

# プロジェクトディレクトリに移動
cd my-emotion-app

このコマンドで、TypeScript に対応した React プロジェクトが生成されます。

ステップ 2:Emotion パッケージのインストール

Emotion の必要なパッケージをインストールします。

bash# Emotion のコアパッケージをインストール
yarn add @emotion/react @emotion/styled
bash# Vite 用の Emotion プラグインをインストール
yarn add -D @emotion/babel-plugin vite-plugin-emotion

@emotion​/​react は CSS-in-JS の基本機能を、@emotion​/​styled は styled-components ライクな記法を提供します。vite-plugin-emotion は Vite で Emotion を最適化するためのプラグインです。

ステップ 3:TypeScript 設定

tsconfig.json を編集して、Emotion の JSX 設定を追加します。

json{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true
json    "jsx": "react-jsx",
    "jsxImportSource": "@emotion/react",
json    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

重要なのは "jsxImportSource": "@emotion​/​react" の設定です。これにより、Emotion の css prop が TypeScript で正しく認識されます。

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

vite.config.ts を編集して、開発高速化とソースマップの最適設定を行います。

基本設定(インポート部分)

typescriptimport { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

プラグイン設定

typescript// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react({
      jsxImportSource: '@emotion/react',
      babel: {
        plugins: ['@emotion/babel-plugin'],
      },
    }),
  ],

この設定により、Emotion の最適化が自動的に適用されます。@emotion​/​babel-plugin がスタイルの抽出と最適化を行います。

開発サーバー設定

typescript  server: {
    port: 3000,
    open: true,
    // HMR の高速化設定
    hmr: {
      overlay: true,
    },
  },

ポート 3000 で開発サーバーを起動し、ブラウザを自動で開きます。HMR のオーバーレイ表示も有効化します。

ソースマップ最適設定(開発環境)

typescript  build: {
    sourcemap: true,
    // 開発時の最適化
    minify: false,
    rollupOptions: {
      output: {
        sourcemapExcludeSources: false,
      },
    },
  },
})

sourcemap: true で詳細なソースマップを生成します。開発時は minify: false にすることで、デバッグしやすいコードが出力されます。

開発高速化のための詳細設定

以下は、開発体験をさらに向上させるための追加設定です。

依存関係の最適化

typescriptexport default defineConfig({
  // ... 前述の設定に追加
  optimizeDeps: {
    include: ['@emotion/react', '@emotion/styled'],
    // 事前バンドルで起動を高速化
    force: false,
  },
typescript  // ビルドキャッシュの活用
  cacheDir: 'node_modules/.vite',
})

optimizeDeps の設定により、Emotion の依存関係が事前にバンドルされ、開発サーバーの起動が高速化されます。

環境別ソースマップ設定

開発環境と本番環境で異なるソースマップ設定を適用する方法を示します。

typescriptimport { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '')
  const isDev = mode === 'development'
typescript  return {
    plugins: [
      react({
        jsxImportSource: '@emotion/react',
        babel: {
          plugins: ['@emotion/babel-plugin'],
        },
      }),
    ],
typescript    build: {
      // 開発: 'source-map', 本番: false or 'hidden-source-map'
      sourcemap: isDev ? 'source-map' : false,
      minify: isDev ? false : 'esbuild',
    },
  }
})

開発環境では完全なソースマップを、本番環境ではソースマップを無効化(または hidden)することで、セキュリティとパフォーマンスを両立します。

以下の図は、環境別の設定フローを示しています。

mermaidstateDiagram-v2
  [*] --> CheckMode
  CheckMode --> DevMode: mode === 'development'
  CheckMode --> ProdMode: mode === 'production'

  DevMode --> DevSourceMap: sourcemap = 'source-map'
  DevMode --> NoMinify: minify = false

  ProdMode --> NoSourceMap: sourcemap = false
  ProdMode --> Minify: minify = 'esbuild'

  DevSourceMap --> [*]
  NoMinify --> [*]
  NoSourceMap --> [*]
  Minify --> [*]

図で理解できる要点

  • ビルドモードによって設定を自動で切り替え
  • 開発環境では詳細なソースマップとミニファイなしでデバッグ性を優先
  • 本番環境ではソースマップなし+ミニファイでパフォーマンスとセキュリティを優先

具体例

実践:Emotion でスタイリングされたコンポーネント

実際に Emotion を使ったコンポーネントを作成してみましょう。

基本的な css prop の使用例

まず、最もシンプルな css prop を使った例です。

typescript/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
typescript// プライマリカラーの定義
const primaryColor = '#0070f3';

// スタイルオブジェクトの定義
const buttonStyle = css`
  background-color: ${primaryColor};
  color: white;
  padding: 12px 24px;
  border: none;
  border-radius: 6px;
  font-size: 16px;
  cursor: pointer;
  transition: background-color 0.3s ease;

  &:hover {
    background-color: #0051cc;
  }
`;

この例では、変数 primaryColor を使って動的にスタイルを定義しています。&:hover でホバー時のスタイルも簡潔に記述できますね。

typescript// コンポーネントの実装
export const Button = () => {
  return (
    <button css={buttonStyle}>クリックしてください</button>
  );
};

css prop にスタイルオブジェクトを渡すだけで、スタイルが適用されます。

styled を使った高度な例

次に、@emotion​/​styled を使ったより高度な例を見ていきましょう。

型定義

typescriptimport styled from '@emotion/styled';

// Props の型定義
interface CardProps {
  variant?: 'primary' | 'secondary';
  elevated?: boolean;
}

Props の型を定義することで、TypeScript の型チェックが効きます。

スタイルコンポーネントの作成

typescript// Card コンポーネントの定義
const Card = styled.div<CardProps>`
  padding: 24px;
  border-radius: 8px;
  background-color: ${props =>
    props.variant === 'primary' ? '#f0f7ff' : '#f5f5f5'
  };

  /* elevation の動的適用 */
  box-shadow: ${props =>
    props.elevated
      ? '0 4px 6px rgba(0, 0, 0, 0.1)'
      : 'none'
  };

  transition: box-shadow 0.3s ease;
typescript  &:hover {
    box-shadow: ${props =>
      props.elevated
        ? '0 8px 12px rgba(0, 0, 0, 0.15)'
        : '0 2px 4px rgba(0, 0, 0, 0.05)'
    };
  }
`

Props に応じて動的にスタイルを切り替えています。elevated プロパティで影の有無を制御できます。

使用例

typescriptexport const CardExample = () => {
  return (
    <>
      <Card variant='primary' elevated>
        プライマリカード
      </Card>

      <Card variant='secondary'>セカンダリカード</Card>
    </>
  );
};

型安全な Props により、IDE の補完も効いて開発効率が上がります。

ソースマップを活用したデバッグ

Vite の設定が正しく行われていれば、ブラウザの開発者ツールで元のコードを参照できます。

デバッグの実践手順

  1. ブラウザで開発サーバー(http:​/​​/​localhost:3000)を開く
  2. Chrome DevTools を開く(F12 または Cmd+Option+I)
  3. Elements タブでスタイルを確認
  4. Sources タブで元の .tsx ファイルを参照

以下の図は、ソースマップを活用したデバッグフローを示しています。

mermaidsequenceDiagram
  participant Dev as 開発者
  participant Browser as ブラウザ
  participant DevTools as DevTools
  participant SourceMap as ソースマップ
  participant Original as 元のコード

  Dev->>Browser: アプリを開く
  Browser->>DevTools: F12 で起動
  DevTools->>SourceMap: スタイル情報を要求
  SourceMap->>Original: 元の位置を解決
  Original->>DevTools: src/App.tsx:25 を表示
  DevTools->>Dev: デバッグ情報を提示

図のポイント

  • ソースマップにより、トランスパイル後のコードから元のコードへ逆引きが可能
  • DevTools で直接元のファイル名と行番号が表示される
  • デバッグ効率が劇的に向上する

よくあるエラーと解決方法

エラー 1:ソースマップが見つからない

arduinoError: Source map not found
DevTools failed to load source map: Could not load content for http://localhost:3000/src/App.tsx.map

発生条件

  • vite.config.tssourcemapfalse になっている
  • ビルドキャッシュが古い

解決方法

  1. vite.config.ts を確認
typescriptexport default defineConfig({
  build: {
    sourcemap: true, // これが true になっているか確認
  },
});
  1. キャッシュをクリアして再起動
bash# node_modules/.vite のキャッシュを削除
rm -rf node_modules/.vite

# 開発サーバーを再起動
yarn dev

エラー 2:Emotion の css prop が認識されない

typescriptTypeError: Property 'css' does not exist on type 'DetailedHTMLProps<...>'

発生条件

  • tsconfig.jsonjsxImportSource 設定が漏れている
  • ファイル先頭の JSX Pragma が不足している

解決方法

  1. tsconfig.json を確認
json{
  "compilerOptions": {
    "jsxImportSource": "@emotion/react"
  }
}
  1. または、各ファイルの先頭に Pragma を追加
typescript/** @jsxImportSource @emotion/react */

パフォーマンス計測

Vite のビルド時間と Emotion の実行パフォーマンスを計測する方法を紹介します。

ビルド時間の計測

bash# 開発サーバーの起動時間を計測
time yarn dev
bash# 本番ビルドの時間を計測
time yarn build

通常、Vite + Emotion の環境では以下のような結果が得られます:

#処理時間(目安)
1開発サーバー起動1〜3 秒
2初回ページロード0.5〜1 秒
3HMR 反映0.1〜0.3 秒
4本番ビルド5〜15 秒

Emotion のランタイムパフォーマンス確認

Chrome DevTools の Performance タブで、Emotion のスタイル適用コストを確認できます。

typescript// パフォーマンス計測用のラッパー
export const measureStylePerformance = () => {
  performance.mark('style-start');

  // Emotion のスタイルを適用
  const element = document.querySelector(
    '.emotion-element'
  );

  performance.mark('style-end');
  performance.measure(
    'emotion-style',
    'style-start',
    'style-end'
  );

  const measure =
    performance.getEntriesByName('emotion-style')[0];
  console.log(
    `Emotion スタイル適用時間: ${measure.duration}ms`
  );
};

このコードで、Emotion のスタイル適用にかかる時間を計測できます。通常は 1ms 以下で完了します。

トラブルシューティング一覧

よくある問題と解決策をまとめました。

#問題原因解決策
1スタイルが適用されないJSX Pragma 未設定tsconfig.jsonjsxImportSource を追加
2HMR が動作しないVite プラグイン設定ミスvite.config.ts で Emotion プラグインを確認
3ビルドが遅い依存関係の最適化不足optimizeDeps を設定
4型エラーが出るEmotion の型定義不足@emotion​/​react を再インストール
5ソースマップがずれるビルド設定の不一致sourcemapExcludeSources: false を設定

まとめ

この記事では、Emotion と Vite を組み合わせた開発環境の最短構築方法と、開発高速化のための設定、そしてデバッグ効率を最大化するソースマップの最適設定について解説しました。

重要なポイントをおさらいしましょう:

  1. 最短構築yarn create vite でプロジェクトを作成し、必要なパッケージをインストールするだけで、すぐに始められます
  2. TypeScript 設定jsxImportSource を設定することで、型安全な Emotion 開発が可能になります
  3. Vite 設定vite.config.ts で Emotion プラグインと HMR を適切に設定すれば、瞬時にスタイル変更が反映されます
  4. ソースマップ:開発環境では詳細なソースマップを、本番環境では無効化することで、デバッグ効率とセキュリティを両立できます
  5. パフォーマンス:依存関係の最適化とビルドキャッシュの活用で、開発体験がさらに向上します

Emotion × Vite の組み合わせは、モダンな React 開発において最高の開発体験を提供してくれます。この記事で紹介した設定を活用すれば、スタイリングの変更が瞬時に反映され、デバッグも快適に行えるでしょう。

ぜひ実際にプロジェクトで試してみてください。きっと、これまでの開発環境とは比較にならないほど快適な体験が得られるはずです。

関連リンク

;