Next.jsで環境別にAPIの接続先を切り替えてみた

# はじめに
チャットアプリに手を入れ始めて、そろそろAWSにもデプロイできるようにしておこうかな。と。

そこで、環境別にバックエンドのAPIを切り変えたいと。
同じような方がいらっしゃるかわかりませんが、ご参考になれば幸いです。

# やりたいこと
以下の６パターンを切り変えたい。
IDE = VsCode 

| No | フロント | バック | 用途 |
|:-:|:-:|:-:|:--|
|1| IDE  | モック | ゴリゴリフロントを改修時
|2| IDE  | IDE | バック改修時にちょっとフロントから動かしたい時
|3| IDE  | Docker | バック起動するのがめんどいくさい時
|4| IDE  | AWS | AWSデプロイの動作確認時
|5| Docker  | Docker | 自宅の運用時
|6| AWS  | AWS | 誰かに見せる時

# ハマったこと
Next.jsは、NODE_ENVという環境変数で、development、production、testが分かれる。

https://nextjs-ja-translation-docs.vercel.app/docs/basic-features/environment-variables

自分がやりたいのは、6パターン。

なので、Next.jsはパターンにハマらない・。色々やればなんとかなりそうかも？
でも、分かりづらい気もする。どうしよう。というところから始まりました。

# どうしたか？
NODE_ENVはいじらずに、新たにBACK_APP_ENVを用意しました。

https://zenn.dev/jj/articles/next-js-env-best-practice

の方の記事を読んで、自分のやりたいことにしっくりきました。

# 考え方
## NODE_ENV
IDE OR AWS/Docker 等のフロントエンドが動いている環境
## BACK_APP_ENV
MOCK/IDE/AWS/Docker バックエンドの環境

## 組み合わせ
| NODE_ENV | BACK_APP_ENV | IDEの起動時コマンド 
|:-:|:-:|:-:|
| development | mock | npm run dev |
| development | ide | npm run dev:ide |
| development | aws | npm run dev:aws |
| development | prod | npm run dev:prod |
| production | aws | - |
| production | prod | - |

# 仕組み
## IDE
１．configファイルをBACK_APP_ENV毎に作成
<details><summary>details</summary>
例）config/ide.json

```
{
  "API_ORIGIN": "localhost:8080"
}
```
</details>

２．next.config.ts で configファイルを読み込む。
※ クライアント環境で利用するので、「NEXT_PUBLIC_」をつけるのが手間なので。nextConfigのenvにも追加。

<details><summary>details</summary>
■ next.config.ts

```
import type { NextConfig } from "next";
import ideConfig from "./config/ide.json";
import awsConfig from "./config/aws.json";
import prodConfig from "./config/prod.json";

const backAppEnv = process.env.BACK_APP_ENV || "mock";

let selectedConfig: Record<string, string>;

switch (backAppEnv) {
  case "ide":
    selectedConfig = ideConfig;
    break;
  case "aws":
    selectedConfig = awsConfig;
    break;
  case "prod":
    selectedConfig = prodConfig;
    break;
  default:
    selectedConfig = {};
    break;
}

const nextConfig: NextConfig = {
  env: {
    BACK_APP_ENV: backAppEnv,
    ...selectedConfig,
  },
  output: "export",
  images: {
    unoptimized: true,
  },
};

export default nextConfig;
```

</details>

３．package.json で起動時に環境変数を設定
※ Windows環境なので、set コマンドを利用。
<details><summary>details</summary>
■ package.json

```
～ 中略 ～
 "scripts": {
    "dev:ide": "set BACK_APP_ENV=ide&&next dev --turbopack",
    "dev:prod": "set BACK_APP_ENV=prod&&next dev --turbopack",
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  ～ 中略 ～
```
</details>
４．app\mocks\msw-provider.tsx の モック設定に、BACK_APP_ENVの条件を追加

https://qiita.com/tarosuke777000/items/622e5ce3e3ace102560a

<details><summary>details</summary>

■ msw-provider.tsx

```
～ 中略 ～
const mockingEnabledPromise =
  process.env.NODE_ENV === "development" &&
  process.env.BACK_APP_ENV === "mock" &&
  typeof window !== "undefined"
    ? import("./browser").then(async ({ worker }) => {
        await worker.start();
        worker.use(...handlers);
      })
    : Promise.resolve();
～ 中略 ～
```
</details>

## Docker
１．DockefileでBACK_APP_ENVの引数を受け取り、環境変数に設定
<details><summary>details</summary>
■ Dockerfile

```
# Stage1
FROM node:21-alpine AS builder

ARG BACK_APP_ENV=prod
ENV BACK_APP_ENV=${BACK_APP_ENV}

WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install

～ 中略 ～

```

</details>

２．docker-compose.ymlにAWS用、自宅用のサービスを分けて定義して、引数を設定

<details><summary>details</summary>
■ docker-compose.yml

```
services:
  nginx:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        BACK_APP_ENV: prod
    ports:
      - "11180:80"
    restart: always
    container_name: nextjs-hc

  nginx-aws:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        BACK_APP_ENV: aws
    ports:
      - "11180:80"
    restart: always
    container_name: nextjs-hc
```

</details>


３．docker-composeでビルド、起動時にサービス名を指定
```
docker compose down nginx
docker compose up -d --build nginx
```

※ AWSは、まだ試せていなく静的ファイルのみのため、S3のみにするかも？しれないので追々変更するかもです。

# やってみての感想
当初は、NODE_ENVにパターン追加も考えましたが、Next.jsの用意している状態をいじるの危ないかな。と。

フロントで利用する環境変数だったので、NEXT_PUBLIC周りでもだいぶハマりました。

# お世話になったサイト
## ENVの考え方
https://zenn.dev/jj/articles/next-js-env-best-practice

## Next.jsの環境変数周り
https://nextjs-ja-translation-docs.vercel.app/docs/basic-features/environment-variables

https://zenn.dev/kazumax4395/articles/643ffc25d3f803

## NEXT_PUBLIC周り
https://zenn.dev/kiwichan101kg/articles/fd6a94b5edc91a

# ソース（今後変わる可能性もありますが。）
https://github.com/tarosuke777/nextjs-hc