Laravel + Sanctum + React + TypeScript + Tailwind CSS + Dockerで開発環境構築

プロジェクトの構成

project-root/
├── docker/              # Docker関連ファイル
│   ├── nginx/           # Nginxの設定
│   ├── php/             # PHPの設定
│   └── mysql/           # MySQLの設定
├── backend/             # Laravelプロジェクト
├── frontend/            # Reactプロジェクト
├── docker-compose.yml   # Docker Compose設定
└── .env                 # 環境変数

1. 必要なフォルダ構造を準備

mkdir sample-project
cd sample-project
mkdir -p docker/nginx docker/php docker/mysql

2. Dockerの設定

docker-compose.yml の作成

プロジェクトのルートディレクトリに docker-compose.yml ファイルを作成します。

services:
  # PHPサービス
  app:
    build:
      context: ./docker/php
    volumes:
      - ./backend:/var/www/html
    depends_on:
      - db
    networks:
      - laravel-network
  
  # Nginxサービス
  web:
    build:
      context: ./docker/nginx
    ports:
      - "80:80"
    volumes:
      - ./backend:/var/www/html
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app
    networks:
      - laravel-network

  # MySQLサービス
  db:
    image: mysql:8.0
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: laravel_db
      MYSQL_ROOT_PASSWORD: root
      MYSQL_USER: laravel
      MYSQL_PASSWORD: secret
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - laravel-network

  # Node.jsサービス(React用)
  node:
    image: node:18-alpine
    working_dir: /app
    volumes:
      - ./frontend:/app
    ports:
      - "3000:3000"
    command: sh -c "if [ -f package.json ]; then npm install && npm start; else echo 'Waiting for frontend setup...'; fi"
    networks:
      - laravel-network

networks:
  laravel-network:
    driver: bridge

volumes:
  mysql-data:

PHPの設定

docker/php/Dockerfile を作成します。

FROM php:8.2-fpm

# 必要なパッケージのインストール
RUN apt-get update && apt-get install -y \\
    git \\
    curl \\
    libpng-dev \\
    libonig-dev \\
    libxml2-dev \\
    zip \\
    unzip

# PHPの拡張機能をインストール
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

# Composerのインストール
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# 作業ディレクトリの設定
WORKDIR /var/www/html

# UIDとGIDを設定して権限の問題を回避
RUN usermod -u 1000 www-data
⚠️ /usr/bin/composer の/usrを/userに間違わないように気を付けてください(体験談)。

Nginxの設定

docker/nginx/Dockerfile を作成します。

FROM nginx:1.23-alpine

WORKDIR /var/www/html

Nginxの設定ファイル docker/nginx/default.conf を作成します。

server {
    listen 80;
    index index.php index.html;
    server_name localhost;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/html/public;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \\.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

3. Laravelプロジェクトの作成

Dockerを使用してLaravelプロジェクトを作成します。

# Dockerイメージのビルド
docker compose build

# Laravelプロジェクトを作成
docker compose run --rm app composer create-project laravel/laravel .

# 権限を設定
sudo chown -R $(id -un):$(id -gn) backend
💡 Hint
docker compose run --rm app は、Docker Compose を使って「一時的なコンテナを起動してコマンドを実行し、終了後にそのコンテナを削除する」という操作を行うコマンドです。

一時的に実行するコマンド(artisan, composer, npm など)に使い、一回実行系に最適です。

長時間動かす常駐型サービス(webサーバやDBなど)はdocker compose up を使います。
⚠️ 今回はLaravel 12がインストールされました。
💡 Hint
権限の設定についてはこちらで説明しています。

Laravelの環境設定

backend/.env ファイルを編集して、データベース接続情報を設定します。

DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel_db
DB_USERNAME=laravel
DB_PASSWORD=secret
💡 Hint
docker-compose.ymlのMySQLサービスで設定しているものと同じ値が入ります。

4. Reactプロジェクトの作成

次に、Reactプロジェクトを作成します。

# Reactプロジェクトを作成
docker compose run --rm node sh -c "npx create-react-app . --template typescript"

# 権限を設定
sudo chown -R $(id -un):$(id -gn) frontend

Reactの設定

API通信のためのプロキシ設定を行います。frontend/package.json に以下の行を追加します。

"proxy": "<http://web>"

5. CORSの設定

Laravelで異なるオリジンからのリクエストを許可するために、CORSを設定します。

config/cors.php設定ファイルは、デフォルトで公開していないため作成します。

# cors.phpファイルを作成
docker compose run --rm app php artisan config:publish cors

config/cors.phpを編集して、以下のように設定します。

<?php

return [

    'paths' => ['api/*'],

    'allowed_methods' => ['*'],

    'allowed_origins' => ['<http://localhost:3000>'],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    'supports_credentials' => true,

];

6. Laravel SanctumによるAPI認証の設定

LaravelでAPIの認証を簡単に実装するために、Sanctumを使用します。

# Sanctumのインストール
docker compose run --rm app php artisan install:api

backend/bootstrap/app.php に以下を記述します。

->withMiddleware(function (Middleware $middleware) {
    // apiミドルウェアグループの最後に追加
    $middleware->api(append: [
        \\Laravel\\Sanctum\\Http\\Middleware\\EnsureFrontendRequestsAreStateful::class,
    ]);
})
💡 Hint
Laravel 11以降ではミドルウェアの設定の書き方が変わったようなので注意してください。
こちらを参考にしました。

7. バックエンドAPIの作成

シンプルなAPIを作成してみましょう。

# コントローラーの作成
docker compose run --rm app php artisan make:controller API/TaskController --api

backend/app/Http/Controllers/API/TaskController.php を編集します。

<?php

namespace App\\Http\\Controllers\\API;

use App\\Http\\Controllers\\Controller;
use Illuminate\\Http\\Request;

class TaskController extends Controller
{
    /**
     * タスク一覧の取得
     * 
     * @return \\Illuminate\\Http\\Response
     */
    public function index()
    {
        $tasks = [
            ['id' => 1, 'title' => 'タスク1', 'completed' => false],
            ['id' => 2, 'title' => 'タスク2', 'completed' => true],
            ['id' => 3, 'title' => 'タスク3', 'completed' => false],
        ];

        return response()->json($tasks);
    }
}

APIルートを設定します。backend/routes/api.php を編集します。

<?php

use App\\Http\\Controllers\\API\\TaskController;
use Illuminate\\Http\\Request;
use Illuminate\\Support\\Facades\\Route;

Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:sanctum');

// タスク一覧取得のルート
Route::get('/tasks', [TaskController::class, 'index']);

8. フロントエンドでAPIの利用

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

docker compose run --rm node npm install axios

APIからデータを取得するコンポーネントを作成します。frontend/src/App.tsx を編集します。

import React, { useEffect, useState } from 'react';
import logo from './logo.svg';
import './App.css';
import axios from 'axios';

interface Task {
  id: number;
  title: string;
  completed: boolean;
}

function App() {
  const [tasks, setTasks] = useState<Task[]>([]);
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    // APIからタスク一覧を取得
    const fetchTasks = async () => {
      try {
        const response = await axios.get('/api/tasks');
        setTasks(response.data);
        setLoading(false);
      } catch(err) {
        setError('タスクの取得に失敗しました');
        setLoading(false);
      }
    };

    fetchTasks();
  }, []);

  if (loading) return <div>読み込み中...</div>;
  if (error) return <div>{error}</div>;

  return (
    <div className="App">
      <header className="App-header">
        <h1>タスク一覧</h1>
      </header>
      <main>
        <ul>
          {tasks.map(task => (
            <li key={task.id} style={{ textDecoration: task.completed ? 'line-through' : 'none' }}>
              {task.title}
            </li>
          ))}
        </ul>
      </main>
    </div>
  );
}

export default App;

9. 開発環境の起動

すべての設定が完了したら、Docker Composeを使って開発環境を起動します。

docker compose up -d

これで以下のURLでアプリケーションにアクセスできます:

10. 開発環境の使用方法

Laravelコマンドの実行

# Artisanコマンドの実行
docker compose exec app php artisan <command>

# 例: マイグレーション
docker compose exec app php artisan migrate

# 例: シーダーの実行
docker compose exec app php artisan db:seed

npmコマンドの実行

# npmコマンドの実行
docker compose exec node npm <command>

# 例: パッケージのインストール
docker compose exec node npm install <package-name>

# 例: ビルド
docker compose exec node npm run build

データベースへのアクセス

# MySQLへの接続
docker compose exec db mysql -u laravel -p

11. 本番環境への準備

本番環境にデプロイする前に、以下のステップを実行してください。

フロントエンドのビルド

docker compose exec node npm run build

環境変数の設定

本番環境用の .env ファイルを作成し、適切な設定を行います。

キャッシュの最適化

docker compose exec app php artisan config:cache
docker compose exec app php artisan route:cache
docker compose exec app php artisan view:cache

こちらをとても参考にさせていただきました。

環境による違いが出たので、勉強も兼ねて改めて復習に書いてみました。


[ここから追記]

後からTailwind CSSも入れたくなったので追記します。

Tailwind CSS バージョン 4 以降 では、npx tailwindcss init -p コマンドが使用できないため、よく見かける以下のコマンドではsh: tailwind: not found exit status 127 が起こってしまいました。

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init

そこで調べてみたところ、こちらの2のような方法もあるようですが、今回はcreate-react-appで作ってしまったのでVite環境ではありません。

ですのでTailwindのバージョンを3に下げることで対応します。

docker compose exec node npm install -D tailwindcss@3 postcss autoprefixer
docker compose exec node npx tailwindcss init -p

これでTailwind CSSもインストールできました。

コメント

タイトルとURLをコピーしました