Next.js + MySQL Docker環境のセットアップ記録

# 結論
https://github.com/Daiius/nextjs-test

大体こんな感じになりました。

# 概要
WSL2 内に Next.js 環境を構築したので記録を付けます。
Docker も使えば Next.js サーバとデータベースのやり取りも容易に行えるので、それも目指します。
distrolessを使った本番環境と、yarn dev+ホットリロードができる開発環境の両方を準備します。

# 素の Next.js 環境の構築 (yarn)
1. 公式サイトを参考に node.js 環境を準備します
https://nodejs.org/en/download/package-manager
2. 公式サイトを参考に yarn コマンドをインストールします
https://yarnpkg.com/getting-started/install
3. Next.js 環境構築用のコマンドを実行します
```
$ yarn create next-app --ts
```

# 開発環境 Docker イメージの作成
データベースも一緒にして docker compose 出来ると何かと便利なので、
先ほど構築した素の Next.js 環境と適当なデータベース(今回は MySQL)を一緒に使えるようにします。
先程構築した素の開発環境を volumes オプションでまるまる渡します（もっと良いやり方があるかも？）。
1. Dockerfile.nextjs に開発環境イメージの構成を書きます
（次の docker-compose.yml で volumes 設定をするので、ここには VOLUME 設定を書かないでおきます）
```Dockerfile:Dockerfile.nextjs
FROM node:20

WORKDIR /app

RUN yarn install

CMD ["yarn", "dev"]
```
2. docker-compose.yml を書きます
```yml:docker-compose.yml
services:
  nextjs:
    build:
      dockerfile: ./Dockerfile.nextjs
    container_name: nextjs
    volumes:
      - ./:/app
    ports:
      - 3000:3000
  database:
    image: mysql:8.3.0
    container_name: database
    environment:
      MYSQL_ROOT_PASSWORD: <いい感じのrootパスワード>
      MYSQL_USER: <いい感じのユーザ名>
      MYSQL_PASSWORD: <いい感じのパスワード>
      MYSQL_DATABASE: <いい感じのデータベース名>

networks:
  default:
    name: nextjs-test-network

```
## 開発環境のホットリロード対応
素の Next.js 開発環境をそのまま Docker コンテナに入れると、ホットリロード機能（変更したファイルに対応するページが自動的に再読み込みされる機能）が動かないそうです。
以下のファイルに明示的に再読み込み設定を書くとよいらしいです。
```typescript:next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,      // ついでに Strict Mode を設定（必須ではないです）
  webpack: (config) => {      // ↓ここ以降を追加
    config.watchOptions = {   //
      poll: 1000,             //
      aggregateTimeout: 300   //
    }                         //
    return config;            //
  }                           // ↑ここまで
};

export default nextConfig;

```

# 本番環境用の distroless イメージ環境
Next.js アプリを本番環境にデプロイする際におすすめの手法とのことです。
ただし、yarn コマンドどころか shell 環境すらないので、素の環境とは全く違った感覚でのセットアップが必要になります。

① Dockerfile.nextjs.prod を書きます
```Dockerfile:Dockerfile.nextjs.prod
# 参考: https://zenn.dev/kazumax4395/articles/427cc791f6145b

# Build layer
# devDependenciesも含めてyarn installし、
# .next/ 内にNext.js関連の仕組みが動作するのに必要なファイルを出力
FROM node:20-slim as build

WORKDIR /app

COPY package.json yarn.lock ./

RUN yarn install --non-interactive --frozen-lockfile

COPY . .

#RUN yarn build:next && yarn build:server
# build:serverは必要ないらしい
RUN yarn build:next

# Package install layer
# dependencies をインストール、動作に必要なライブラリだけを取得する
FROM node:20-slim as node_modules
WORKDIR /app
COPY package.json yarn.lock ./

RUN yarn install --non-interactive --frozen-lockfile --prod

# Deploy layer
#
# イメージサイズやセキュリティの視点からおすすめのイメージとのこと
FROM gcr.io/distroless/nodejs20-debian12

WORKDIR /app
ENV NODE_ENV production

COPY package.json yarn.lock next.config.mjs ./
COPY --from=build /app/public ./public
COPY --from=build /app/.next ./.next
# ここでも server/index.ts 関連の指定はいらないらしい
# package.json の start で指定しているからそれで十分なのだろうか
#COPY --from=build /app/dist ./dist
COPY --from=node_modules /app/node_modules ./node_modules

CMD ["node_modules/.bin/next", "start"]

```

② docker-compose-prod.yml を書きます、ほとんど docker-compose.yml ファイルと同じです
```yml:docker-compose-prod.yml
services:
  nextjs:
    build:
      dockerfile: ./Dockerfile.nextjs.prod #ここだけ本番環境用に変更
    container_name: nextjs
    ports:
      - 3000:3000
  database:
    image: mysql:8.3.0
    container_name: database
    environment:
      MYSQL_ROOT_PASSWORD: <いい感じのrootパスワード>
      MYSQL_USER: <いい感じのユーザ名>
      MYSQL_PASSWORD: <いい感じのパスワード>
      MYSQL_DATABASE: <いい感じのデータベース名>

networks:
  default:
    name: nextjs-test-network

```

# 終わりに
NGINX + React 環境で開発してきたので、特にホットリロードをはじめとする Next.js 環境の便利さには目を見張るものがあります！

Next.js の開発環境や、本番環境（ビルド結果）が動作するのにどのファイルが必要で、
どのように配置する必要があるのか、どのように実行する必要があるのか...
完全に把握できるまで、もう少し設定の確認や記事の修正を行おうと思います。

# 参考記事
https://zenn.dev/kazumax4395/articles/427cc791f6145b