👾

Next.jsとLaravel 12のディレクトリを連結させる

に公開

やりたいこと

バックエンドとフロントエンドを別々のディレクトリで管理し、連携させる形にしたい。
一つのアプリにまとめず、以下の構成で運用する。

root/
 ├ backend/
 └ frontend/

手順

まずは別々にフロントとバックエンドを環境構築する

Ftontend(Next.js Typescript)

今回はレイアウトの共有が楽なので、Next.jsを採用しました。

Nextの環境を作る

オプション	内容
--typescript	TypeScriptで作成
--app	App Router(app/ ディレクトリ)使用
--eslint	Lintツール導入(任意)
--tailwind	Tailwind CSS導入(任意)
--src-dir	src/ ディレクトリ構成にする
--import-alias	インポートエイリアス設定

上記のオプションで設定したい時は下記のコードにまとめることが可能です。

npx create-next-app@latest frontend --typescript --app --eslint --tailwind --src-dir --import-alias "@/*"

Would you like to use Turbopack for next dev? › No / Yes
上記の質問が出る場合は、Turbopack という開発用ビルドツールと使うかどうかを聞かれているようなので、Noを選択します(青文字の方が選択中)。

cd frontend
npm run dev

page.tsxを設定させておく

一旦連結しているかどうかを把握するためにsrc/app/page.tsxに下記を追加します。

'use client'

import { useEffect, useState } from 'react'

export default function Home() {
  const [posts, setPosts] = useState([])
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    fetch('http://localhost/api/posts')
      .then(res => {
        if (!res.ok) {
          throw new Error(`HTTPエラー: ${res.status}`)
        }
        return res.json()
      })
      .then(data => {
        console.log('取得データ:', data)
        setPosts(data)
      })
      .catch(err => {
        console.error('Fetch error:', err)
        setError(err.message)
      })
  }, [])

  return (
    <div>
      <h1>Posts</h1>

      {error && (
        <p style={{ color: 'red' }}>
          データ取得エラー: {error}
        </p>
      )}

      {posts.length === 0 && !error && (
        <p>読み込み中...</p>
      )}

      {posts.map((post: any) => (
        <div key={post.id}>{post.title}</div>
      ))}
    </div>
  )
}

これでFrontエンドの表示で連結ができたか確認するための用意ができました。

BackendでLaravel12を用意する

なぜ12と強調するのかというと、Laravel12ではデフォルトではroute/app.phpがないからです。
Laravelで用意するファイルは下記の通り。

ProgreSQLを使用する場合

MySQLでない場合は下記コマンドだと早い。

curl -s "https://laravel.build/backend?with=pgsql" | bash

sail artisan migrateでテーブルを作ります。

route/api.phpを作る

route/api.phpを追加します。
参考にしたのは下記の記事。
https://zenn.dev/idapan/articles/c4a2c2f956ad10
コマンドなしでapi.phpを作ってもOK。

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;

Route::get('/posts', [PostController::class, 'index']);

bootstrap/app.phpに追加

作った後はbootstrap/app.phpにコードを追加。

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->prepend(\Illuminate\Http\Middleware\HandleCors::class);
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        //
    })->create();

デフォルトと違うのは、下記の通り
①api: DIR.'/../routes/api.php',
②->withMiddleware(function (Middleware $middleware): void {
$middleware->prepend(\Illuminate\Http\Middleware\HandleCors::class);
})
これ書かないと、apiを見に行ってくれません。

app/Http/Controllers/PostController.phpを作る

一旦PostControllerを作成。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PostController extends Controller
{
    public function index()
    {
        return response()->json([
            ['id' => 1, 'title' => 'テスト投稿'],
            ['id' => 2, 'title' => 'こんにちは Laravel']
        ]);
    }
}

これでhttp://localhost/api/postsを見に行くと...

jsonが見えてAPIが通っているのがわかります。
ここで404になる時は、api.phpの記述が間違っているか、app.phpが間違っているかです。多分。
http://localhost:3000/を見に行くと下記の通り。

コントローラーに記載した内容を表示できました。

Discussion