【環境構築】Laravel9 + Vite + TypeScript in Docker

モダンっぽそうな環境の構築にトライしたので忘れないうちにメモ

# 環境
- PHP8.1
- Laravel 9
- Vite
- TypeScript
- MySQL

Laravelコンテナ、MySQLコンテナをdocker-compose.ymlで立てる
Docker環境はDocker Desktop

# 目標
- Laravelトップページの表示
- TypeScriptの実行
- Laravel - MySQL間の連携


## 1. dockerfile, docker-compose.ymlを作成
laravelはcomposerで導入
laravel sailというのがあるみたいなので別の機会に試すことにする
```dockerfile:dockerfile
FROM centos:centos7

WORKDIR /var/www/html

RUN	yum -y update && \
	yum install -y https://rpms.remirepo.net/enterprise/remi-release-7.rpm
# php
RUN yum -y install php --enablerepo=remi-php81 \
	php-mbstring \
	php-pdo \
	php-dom \
	php-mysqlhd \
	zip \
	unzip
# composer
RUN curl -sS https://getcomposer.org/installer | php -- --version=2.4.4 && \
	mv composer.phar /usr/local/bin/composer
# node
RUN curl -sL https://rpm.nodesource.com/setup_16.x | bash - && \
	yum -y install nodejs

```

```docker-compose.yml
version: '3'

services:
  web:
    container_name: web
    build: .
    tty: true                         # up後も起動し続けるようにする
    privileged: true                  # systemctlを有効化する
    command: "/sbin/init"             # systemctlを有効化する
    ports:
      - "80:80"
      - "5173:5173"                   # Viteのdevサーバ用ポート
    volumes:
      - ./web:/var/www/html
  db:
    container_name: db
    image: mysql:8.0.15
    tty: true                         # up後も起動し続けるようにする
    environment:
      MYSQL_DATABASE: hoge
      MYSQL_USER: root
      MYSQL_ROOT_PASSWORD: admin
    ports:
      - 3306:3306
    volumes:
      - ./db/data:/var/lib/mysql       # データの永続化マウント
      - ./db/conf.d:/etc/mysql/conf.d # 設定の永続化マウント
```

## 2. コンテナ作成
dockerfile, docker-compose.ymlを適当なディレクトリに置く
今回はDocuments直下にディレクトリを切って配置

こんな感じ↓
> Documents
　└ laravel9
　　├ dockerfile
  　　└ dockercompose.yml

powerShellでコンテナ起動
```powershell:powershell
cd $HOME/Documents/laravel9
docker-compose up -d
```
-dオプションをつけていればバックグラウンドで起動してくれるので、コンテナ立てながら好きなことができる
--buildオプションをつけていれば、upのたびにイメージのビルドからやってくれるらしい

一応確認
それっぽいのが2つ立ち上がってればOKとする
```powershell:powershell
docker ps

CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS                                        NAMES
2b2ab41fb888   laravel9-web   "/sbin/init"             15 seconds ago       Up 13 seconds       0.0.0.0:80->80/tcp, 0.0.0.0:5173->5173/tcp   web
2c984059cd45   mysql:8.0.15   "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:3306->3306/tcp, 33060/tcp            db
```

ディレクトリ構成↓
> Documents
　└ laravel9
　　├ db　　 # MySQLのマウント
　　├ web　　# Laravelのマウント
　　├ dockerfile
  　　└ dockercompose.yml


## 3. Laravel 9
コンテナにインしてインストール実施
```powershell:powershell
docker exec -it web bash
composer create-project laravel/laravel=9.* /var/www/html

Info from https://repo.packagist.org: #StandWithUkraine
...
> @php artisan key:generate --ansi
   INFO  Application key set successfully.
```
envのappkey作成まで自動でやってくれる

早速ビルトインサーバを立てて画面で確認
```powershell:powershell
php artisan serve --host 0.0.0.0 --port=80

Server running on [http://0.0.0.0:80].
```
Dockerコンテナ外から内部サーバを参照できるようにするために``--host 0.0.0.0``をつける
``--port=80``でポートを指定、今回のwebコンテナは80番ポートを開けてあるので80番で設定（5173ポートも開けてるのでそっちの指定もできなくはない）

localhost:80に接続して、トップページが出ればok

## 4. Vite + TypeScript
Viteってそもそも何？って思ったらlaravel-mixみたいなものらしい
vue.jsと作者が同じだとか


### 4.1 Vite導入から確認まで
package.jsonにViteの記載があるか念のため確認
（Laravel8以降?には標準搭載みたい）
```package.json
{
    "private": true,
    "scripts": {
        "dev": "vite",
        "build": "vite build"
    },
    "devDependencies": {
        "axios": "^1.1.2",
        "laravel-vite-plugin": "^0.7.0",
        "lodash": "^4.17.19",
        "postcss": "^8.1.14",
        "vite": "^3.0.0"
    }
}
```
インストール
```powershell:powershell
npm install
```

npm runしてみる
```powershell:powershell
npm run dev

 VITE v3.2.5  ready in 2202 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

  LARAVEL v9.43.0  plugin v0.7.1

  ➜  APP_URL: http://localhost
```
起動した
webpackと全然違うし、しかも早い！
ただ、この状態だとターミナルの操作ができない（=php artisan serveできない）ので、httpdでサーバを立ち上げる
（ターミナルを複数立ち上げとけばいける？でも複数立ち上げたくない）
```powershell:powershell
vi /etc/httpd/conf/httpd.conf

# ドキュメントルートだけ変更
DocumentRoot: /var/www/html/public
```
```powershell:powershell
systemctl start httpd
```

ここで画面エラー
```
The stream or file "/var/www/html/storage/logs/laravel.log" could not be opened in append mode: Failed to open stream: Permission denied The exception occurred while attempting to log: The stream or file
```
よく見るやつ
以下コマンドを実行
```powershell:powershell
chmod -R 777 storage bootstrap/cache 
```
パーミッション周りは何も気にせず777にしがちなので、勉強の余地あり

画面を表示
``npm run dev``しながらでもLaravelトップページが見れるのを確認する


### 4.2 TypeScriptをコンパイルしてみる
公式を参照しつつViteのコンパイルを動かしてみる
https://readouble.com/laravel/9.x/ja/vite.html

resources/jsに以下のファイルを作成
```typescript:app.ts
console.log("ts");
```
resources/views/welcome.blade.phpに@viteディレクティブを追加
```html:welcome.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>Laravel</title>
        @vite('resources/js/app.ts')
```
vite.config.jsのビルド対象を修正
```vite.config.js
export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/js/app.ts'],
            refresh: true,
        }),
    ],
});
```

``npm run dev``して画面を表示

ここでコンソールエラー
```
Failed to load resource: net::ERR_EMPTY_RESPONSE
```
jsが読めてない
出力されているhtmlを確認
```html
<title>Laravel</title>
<script type="module" src="http://127.0.0.1:5173/@vite/client"></script>
<script type="module" src="http://127.0.0.1:5173/resources/js/app.ts"></script>
```
さっきの@viteディレクティブはこんな感じで展開される
``npm run dev``によって、viteのdevサーバが立ち上げられ、そこからファイルを読み取っているイメージ
→``http://127.0.0.1:5173``になっているので、これを``http://localhost:5173``にする

vite.config.jsを修正
server設定を追加
```vite.config.js
export default defineConfig({
    server: {
        host: true,
        hmr: {
            host: "localhost"
        },
        watch: {
            usePolling: true
        }
    },
    plugins: [
        laravel({
            input: ['resources/js/app.ts'],
            refresh: true,
        }),
    ],
});
```
設定については公式に説明があります

https://vitejs.dev/config/server-options.html


``watch: { usePolling: true }``はwindows + WSL2環境下で監視を動作させるための設定
公式にもあるので引用

>Linux 用 Windows サブシステム (WSL) 2 での Vite の使用
>
>WSL2 で Vite を実行している場合、ファイルが Windows アプリケーション (非 WSL2 プロセス) によって編集されている場合、ファイル システム監視は機能しません。これは、WSL2 の制限によるものです。これは、WSL2 バックエンドを使用して Docker で実行する場合にも当てはまります。

これを設定しておくと、
tsかwelcome.blade.phpに変更が入った時、自動で画面リロードが走るようになる


``npm run dev``して画面を表示し、console.logが出てればok
tsファイルを変更して自動反映されるかどうかも確認しておく


## 5. MySQL
いつものようにDB接続先を設定
```.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=hoge
DB_USERNAME=root
DB_PASSWORD=admin
```
migrate実行でエラー発生
```powershell:powershell
php artisan migrate

SQLSTATE[HY000] [2002] Connection refused
```
色々調べたところ「DB_HOST」の値はdocker-compose.ymlで設定しているDBのservice名にしないといけないらしいので、下記に変更
```diff:.env
DB_CONNECTION=mysql
- DB_HOST=127.0.0.1
+ DB_HOST=db
DB_PORT=3306
DB_DATABASE=hoge
DB_USERNAME=root
DB_PASSWORD=admin
```

migrate実行で通るのを確認


# 所感
Viteすごい
docker-compose.ymlも触ったことなかったけどこれもすごい