Reactでビルドした後に環境変数を設定する

# 概要

Reactでは環境変数がビルド時に固定化されます。そのためテスト環境と本番環境で異なる環境変数を設定するには、通常はそれぞれ異なるビルドを出力する必要があります。

そこで今回は、同じビルドを出力してテスト環境と本番環境にデプロイしたのち、それぞれの実行環境で異なる環境変数を設定する特殊な方法を紹介します。

# 準備

Reactプロジェクトを新規作成します。（Viteを使います。）

```bash
npm create vite@latest react-app -- --template react-swc-ts

cd react-app
npm install
```

環境変数を`.env.development.local`ファイルに設定します。

```bash:.env.development.local
VITE_TITLE="Reactアプリ（開発環境）"
VITE_API_BASEURL="http://localhost:8000"
VITE_MSAL_CLIENT_ID="00000000-0000-0000-0000-000000000000"
VITE_MSAL_AUTHORITY="https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000"
VITE_MSAL_REDIRECT_URL="http://localhost:5173"
```

設定した環境変数を使います。

まず`src/vite-env.d.ts`を編集して、型を定義します。

```ts:src/vite-env.d.ts
/// <reference types="vite/client" />

interface ImportMetaEnv {
  readonly VITE_TITLE: string;
  readonly VITE_API_BASEURL: string;
  readonly VITE_MSAL_CLIENT_ID: string;
  readonly VITE_MSAL_AUTHORITY: string;
  readonly VITE_MSAL_REDIRECT_URL: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}
```

次に`src/App.tsx`を編集して、環境変数を使います。

```tsx:src/App.tsx
import "./App.css";

const App = () => {
  return (
    <>
      <h1>{import.meta.env.VITE_TITLE}</h1>
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>Value</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>TITLE</td>
            <td>{import.meta.env.VITE_TITLE}</td>
          </tr>
          <tr>
            <td>API_BASEURL</td>
            <td>{import.meta.env.VITE_API_BASEURL}</td>
          </tr>
          <tr>
            <td>MSAL_CLIENT_ID</td>
            <td>{import.meta.env.VITE_MSAL_CLIENT_ID}</td>
          </tr>
          <tr>
            <td>MSAL_AUTHORITY</td>
            <td>{import.meta.env.VITE_MSAL_AUTHORITY}</td>
          </tr>
          <tr>
            <td>MSAL_REDIRECT_URL</td>
            <td>{import.meta.env.VITE_MSAL_REDIRECT_URL}</td>
          </tr>
        </tbody>
      </table>
    </>
  );
};

export default App;
```

さらに`index.html`を編集して、ここでも環境変数を使います。

```html:index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>%VITE_TITLE%</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>
```

開発モードで実行します。

```bash
npm run dev
```

環境変数が反映されることを確認します。

![スクリーンショット 2023-12-16 17.09.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268124/ad9cdfe7-558b-bf44-f5ad-17cf799878f5.png)

# ビルドした後に環境変数を設定する

`.env.production`ファイルを下記のように作成し、ビルド時に環境変数をいったん`MYAPP_***`という値で固定化します。

```bash:.env.production
VITE_TITLE=MYAPP_TITLE
VITE_API_BASEURL=MYAPP_API_BASEURL
VITE_MSAL_CLIENT_ID=MYAPP_MSAL_CLIENT_ID
VITE_MSAL_AUTHORITY=MYAPP_MSAL_AUTHORITY
VITE_MSAL_REDIRECT_URL=MYAPP_MSAL_REDIRECT_URL
```

ビルドで固定化された`MYAPP_***`という値を、実行環境の環境変数値に置換するシェルスクリプト`replace-react-env.sh`を作成します。

```sh:replace-react-env.sh
#!/bin/sh

# ビルド出力先を指定します。
outDir="dist"

# ビルド出力ファイルの一覧を取得します。
files=$(find "$outDir" -type f)
# 実行環境の環境変数のうち`MYAPP_`から始まる環境変数名の一覧を取得します。
vars=$(printenv | grep '^MYAPP_' | awk -F= '{print $1}')

for file in $files; do
  for var in $vars; do
    # 実行環境での環境変数`MYAPP_***`の値を取得します。
    value=$(printenv "$var")
    # ファイルの中にある`MYAPP_***`という文字列を実行環境の環境変数値に置換します。
    sed -i "s#$var#$value#g" "$file"
  done
done

```

これにより、Reactをビルドして実行環境にデプロイしたのち`replace-react-env.sh`を実行すると、環境変数はビルド時に固定化された値ではなく、実行環境の環境変数値が反映されるようになります。

|段階|環境変数の状態|
|---|---|
|開発中|`import.meta.env.VITE_***`（もしくは`%VITE_***%`）という式|
|ビルド後|`MYAPP_***`という文字列|
|実行環境にデプロイ＆`replace-react-env.sh`実行後|実行環境での環境変数`MYAPP_***`の値|

# 動作確認

Reactをビルドします。

```bash
npm run build
```

いったんプレビュー確認します。

```bash
npm run preview
```

この時点では`.env.production`で設定した`MYAPP_***`という値が反映されます。

![スクリーンショット 2023-12-16 17.56.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268124/14a93ca6-a471-ef52-c2e7-cdf14d5c284a.png)

実行環境の環境変数を設定します。

```bash
export MYAPP_TITLE="Reactアプリ（本番環境）"
export MYAPP_API_BASEURL="https://prod-sample.com/api"
export MYAPP_MSAL_CLIENT_ID="11111111-1111-1111-1111-11111111"
export MYAPP_MSAL_AUTHORITY="https://login.microsoftonline.com/11111111-1111-1111-1111-11111111"
export MYAPP_MSAL_REDIRECT_URL="https://prod-sample.com"
```

`replace-react-env.sh`を実行します。（`chmod u+x replace-react-env.sh`で実行権限を付与しておきます。）

```bash
./replace-react-env.sh
```

再びプレビュー確認します。

```bash
npm run preview
```

実行環境の環境変数値が反映されることを確認します。

![スクリーンショット 2023-12-16 18.22.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268124/00755e16-7729-f17d-43a3-d6c7b063feba.png)