Laravel環境再度作り直し

パクリ35発目!!
前回から4か月経ってたか今回も。どの環境を使ってたかを思い出すのを一苦労。

パクリ元

内容

前回パーミッション部分ごまかして作ってたけどやっぱり作り直さないと不便と気づいて作り直した件。

API関連機能やり直し

さてパクリ元1つ目から routes/api.phpがない の記事を見つけ、おーおーそんなこともあったなと前回の記事を読み直す。

どうも hoge API が見つからないようだ。パクリ元6つ目を参考に api.php を読ませるようにする。昔作った時は自動的に読まれてたような気がするがまあいい。

composer.lock を見直すと、laravel/framework は v11.34.1 とある、そうだったか!
laravel11 の作法に従って、前回 AppServiceProvider に追加した箇所をコメントアウトに戻し、作成した routes/api.php を routes/api.php_ に変更しておく。

app/Providers/AppServiceProvider.php
・・・
use Illuminate\Support\Facades\Route;
・・・
public function boot(): void
{
    //
}
・・・

どうも laravel11 では bootstrap/app.php が重要視されてきたようなので確認しておく。

bootstrap/app.php
・・・
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        //
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

API関連の機能 をインストールする。

~/example-app$ sail artisan install:api
Sail is not running.

You may Sail using the following commands: './vendor/bin/sail up' or './vendor/bin/sail up -d'

おっと、いろいろ忘れてる。何も覚えてない。起動コマンドは表示されているが、一応前回記事全部見返す。備忘録ホント大事。

~/example-app$ ./vendor/bin/sail up -d
・・・
~/example-app$ ./vendor/bin/sail artisan install:api
・・・
One new database migration has been published. Would you like to run all pending database migrations? (yes/no) [yes]:
 > yes
・・・

bootstrap/app.php が変更され、routes/api.php も作成されているのを確認したので、前回追加した API も追加しておく。

bootstrap/app.php
・・・
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
・・・
routes/api.php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

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

/// 追加しておく
Route::get('/hoge', function (Request $request) {
    return response()->json(
        [
            'hoge' => 'Hello from Laravel'
        ]
    );
});

クッソー保存できませんでしただと!?そうか、docker内部にファイルは読み込み専用でしか作成できなかったのか、、また少し思い出してきた。artisan 経由でファイルを作成するたびにこのトラップに引っかかることは容易に想像できる。しょうがない、やり直そう。。

再々度 laravel 環境作成

パクリ元2つ目の情報によると以下との事。

対応策は3つあります。

  1. Laravelディレクトリ・ファイルの所有者の変更
  2. エラー対象のディレクトリ・ファイルのパーミッションの変更
  3. 一般ユーザーでLaravelをインストールする

1、2は新しいファイルを artisan 経由(コンテナ内)で作ったら毎回影響ありそうなので 3 で対応してみよう。そこで、作成された routes/api.php の権限を確認してみる。

~/example-app$ ls -al routes/api.php
-rw-r--r-- 1 1337 ubuntu 186 Apr  4 23:14 routes/api.php
~/example-app$ id ubuntu 
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),117(netdev),999(docker)

つまり、uid=1337、gid=1000 のユーザーでコンテナ内から作られたことになる。docker-compose.yml に記述されている ./vendor/laravel/sail/runtimes/8.4/Dockerfile を見ると該当箇所が見つかった。

vendor/laravel/sail/runtime/8.4/Dockerfile
・・・
RUN useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail
・・・

なるほど。これらを踏まえ、前回の Docker までインストールしたイメージを利用して、ホスト側も同じIDの一般ユーザーを作成して Laravel をインストールしてみることにする。はじめにパクリ元2つ目を参考に root にてユーザーを作成し、uid/gid を設定する。

~#  adduser sail
Adding user `sail' ...
Adding new group `sail' (1001) ...
Adding new user `sail' (1001) with group `sail' ...
Creating home directory `/home/sail' ...
Copying files from `/etc/skel' ...
New password:
Retype new password:
passwd: password updated successfully
Changing the user information for sail
Enter the new value, or press ENTER for the default
        Full Name []:
        Room Number []:
        Work Phone []:
        Home Phone []:
        Other []:
Is the information correct? [Y/n] Y
~# usermod -aG sudo sail
~# usermod -aG docker sail
~# usermod -u 1337 sail
~# usermod -g 1000 sail
~# id sail
uid=1337(sail) gid=1000(ubuntu) groups=1000(ubuntu),27(sudo),999(docker)
~# su - sail
・・・
~$

IDを揃えた一般ユーザーでパクリ元3つ目に従って laravel をインストールする。

~$ curl -s "https://laravel.build/example-app" | bash
・・・
・・・(結構長い)
・・・
[sudo] password for sail:
Thank you! We hope you build something incredible. Dive in with: cd example-app && ./vendor/bin/sail up
~$ cd example-app/
~/example-app$ ./vendor/bin/sail up -d
[+] Running 10/10
 ✔ Network example-app_sail               Created      0.2s
 ✔ Volume "example-app_sail-meilisearch"  Created      0.0s
 ✔ Volume "example-app_sail-mysql"        Created      0.0s
 ✔ Volume "example-app_sail-redis"        Created      0.0s
 ✔ Container example-app-selenium-1       Started      0.8s
 ✔ Container example-app-mysql-1          Started      0.8s
 ✔ Container example-app-meilisearch-1    Started      0.8s
 ✔ Container example-app-mailpit-1        Started      0.9s
 ✔ Container example-app-redis-1          Started      0.7s
 ✔ Container example-app-laravel.test-1   Started      1.2s
~/example-app$ 

立ち上がったようなので http://localhost/ へアクセス。

前回のようなパーミッションエラーはなく、Laravel11由来のテーブルがないエラーになった。うまくいったようなので、あとは前回終わりまでの対応を機械的に行う。

マイグレーションして localhost を確認する。

~/example-app$ ./vendor/bin/sail artisan migrate

正常に表示された!が、新しい画面になってる。。

phpMyAdmin

パクリ元3つ目に戻って phpMyAdmin のインストール。

docker-compose.yml
services:
+   phpmyadmin:
+       image: phpmyadmin/phpmyadmin
+       links:
+           - mysql:mysql
+       ports:
+           - 8888:80
+       environment:
+           PMA_HOST: mysql
+       networks:
+           - sail
    laravel.test:
・・・

再起動する。

~/example-app$ ./vendor/bin/sail stop
~/example-app$ ./vendor/bin/sail up -d

http://localhost:8888/ にアクセスして root と password でログイン。

右の方に表示されているバージョンが前回とはいくらか変わっているようだ。

react

続いてフロントエンド。パクリ元4つ目を参考にする。sail のエイリアス作成して node 等のバージョンを確認する。

~/example-app$ echo "alias sail='[ -f sail ] && bash sail || bash vendor/bin/sail'" >> ~/.bashrc
~/example-app$ source ~/.bashrc
~/example-app$ sail node --version
v22.14.0
~/example-app$ sail npm --version
11.2.0
~/example-app$ sail npx --version
11.2.0

やはりバージョンがアップしている。自分だけが取り残されているようだ。

~/example-app$ sail npm install
・・・
found 0 vulnerabilities

前回のようなパーミッション問題はなし。次に react 関連インストール。

~/example-app$ sail npm install -D react react-dom @types/react @types/react-dom react-router-dom @types/react-router-dom @vitejs/plugin-react typescript
・・・
found 0 vulnerabilities
~/example-app$ sail npx tsc --init --jsx react-jsx
・・・

以下のファイルを編集または作成する。resouces/views/welcome.blade.php は削除する。

vite.config.js
・・・
        laravel({
            //input: ['resources/css/app.css', 'resources/js/app.js'], // ←コメントアウト
            // typescriptとsassが使えるように変更// ←追加
            input: [// ←追加
                'resources/sass/app.scss', // ←追加
                'resources/ts/index.tsx'// ←追加
            ],// ←追加
            refresh: true,
        }),
・・・
resouces/views/index.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>sample-api</title>

        {{-- react に変更があったとき自動で --}}
        @viteReactRefresh
        @vite(['resources/sass/app.scss', 'resources/ts/index.tsx'])

    </head>

    <body class="antialiased">
        <div id="app"></div>
    </body>
</html>
resources/ts/index.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';

const container = document.getElementById('app');
const root = createRoot(container!); // createRoot(container!) if you use TypeScript

root.render(
  // <React.StrictMode>
    <div className="text-red">
        Hello World
    </div>
// </React.StrictMode>,
);
routes/web.php
・・・
Route::get('/', function () {
    return view('index');
});

Sass も同様に導入する。

~/example-app$ sail npm install -D sass

resources/sass/app.scss を作成して、resources/css/app.css は削除する。

resources/sass/app.scss
.text-red {
    color: red;
}

http://localhost/ にて動作確認する。

~/example-app$ sail npm run dev

react 単体問題なし。

laravel 連携

続いて App.tsx作成、index.tsx 編集、api.php 作成。

resources/ts/App.tsx
import React, { useEffect } from 'react';
import axios from 'axios';

const App: React.FC = () => {
    useEffect(()=>{
        const fetchFromLaravel = async () => {
            const res  = await axios.get(`/api/hoge`);
            alert(res.data.hoge)
        };
        fetchFromLaravel();
    }, [])

    return (
        <div className="App"></div>
    );
}

export default App;
resources/ts/index.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App'; // <- 追加

const container = document.getElementById('app');
const root = createRoot(container!); // createRoot(container!) if you use TypeScript

root.render(
  // <React.StrictMode>
    <div className="text-red">
        {/* Hello World */}
        <App /> {/* <- 追加 */}
    </div>
// </React.StrictMode>,
);

冒頭部分より、api.php は laravel11 では明示的に追加する必要がある。

~/example-app$ sail artisan install:api
・・・
One new database migration has been published. Would you like to run all pending database migrations? (yes/no) [yes]:
 > yes
・・・
routes/api.php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

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

Route::get('/hoge', function (Request $request) {
    return response()->json(
        [
            'hoge' => 'Hello from Laravel'
        ]
    );
});

再び http://localhost/ にて動作確認する。

ここでエクスポートしちゃうよー

D:\wsl> wsl --export Ubuntu-22.04_docker Ubuntu-22.04_laravel_react.tar

雑感

久しぶりに進めようと気合い入れたのに前回のやり直しで終わってしまったという、