ていねいにViteの環境変数について確認する

## はじめに
前回の記事では、Viteにおいて環境ごとに環境変数を使い分ける方法を紹介しました。

今回の記事では、改めてViteでの環境変数とモードの設定について、基本から詳しく解説していきます。

## Viteの環境変数
Viteでは、環境変数を`import.meta.env`オブジェクトを通じて利用できます。

### 組み込みの環境変数
独自の環境変数を利用できるのはもちろん、組み込みの環境変数も用意されています。
```typescript:組み込みの環境変数
console.log(import.meta.env.MODE);  // アプリが動作しているモード
console.log(import.meta.env.BASE_URL);  // アプリのベースURL
console.log(import.meta.env.PROD);  // プロダクションモードかどうか
console.log(import.meta.env.DEV);  // 開発モードかどうか
console.log(import.meta.env.SSR);  // サーバーサイドレンダリングかどうか
```

### 環境変数の定義
カスタムの環境変数は以下のように定義します。
```properties
VITE_API_URL=https://api.example.com
DB_PASSWORD=supersecret
```
ここで注意が必要なのは、`VITE_`プレフィックスです。
このプレフィックスがついた変数のみが、クライアントサイドのコードで利用可能になります。
```typescript:利用例
console.log(import.meta.env.VITE_API_URL);  // https://api.example.com
console.log(import.meta.env.DB_PASSWORD);  // undefined
```

プレフィクスなしの環境変数は、サーバサイドでの処理や`vite.config.js`などのビルドプロセス内で使用します。

うっかり誤ってクライアント側のソースに書いても公開されないため、APIキーやデータベース接続情報など、クライアントに露出させたくない機密情報を保存するのに適しています。

また、Viteはdotenv-expandを使用しているため、環境変数内で他の変数を参照できます。
```properties
KEY=value
REFERENCE=$KEY # "value"として展開される
```

### プレフィックスのカスタマイズ
デフォルトでは`VITE_`プレフィックスの付いた環境変数のみが公開されますが、これは`vite.config.ts`の`envPrefix`オプションでカスタマイズできます。
```typescript:vite.config.ts
export default defineConfig({
	envPrefix: 'PUBLIC_'
});
```

### 環境変数のパース
環境変数は常に文字列として扱われます。
```properties:.env
VITE_PORT=3000
VITE_FEATURE_FLAG=true
```
```typescript:使用時
console.log(typeof import.meta.env.VITE_PORT); // "string"
console.log(typeof import.meta.env.VITE_FEATURE_FLAG); // "string"
```
そのため、使用時には必要に応じて型変換を行う必要があります。
以下は型変換の例です。

```typescript:型変換例
const port = parseInt(import.meta.env.VITE_PORT, 10);
const featureFlag = import.meta.env.VITE_FEATURE_FLAG === 'true';
```


### 環境変数の動的な使用
環境変数は条件分岐にも使用できます。以下は開発環境と本番環境でAPIエンドポイントを切り替える例です。
```typescript
// DEV環境とそうでない場合で切り替える
const apiUrl = import.meta.env.DEV 
  ? 'http://localhost:3000/api' 
  : 'https://api.example.com';

fetch(`${apiUrl}/users`)
  .then(response => response.json())
  .then(data => console.log(data));
```

### モードについて
Viteには「モード」という概念があります。
デフォルトでは以下のように設定されています。

viteコマンド実行時：developmentモードで起動
vite buildコマンド実行時：productionモードで起動

#### モードのカスタマイズ
モードは`--mode`オプションで変更できます。
例えば
```bash
vite build --mode staging
```
このコマンドを実行すると、Viteは`.env.staging`ファイルを読み込みます。

#### NODE_ENVとモードの関係
`NODE_ENV`とモードは別の概念です。
以下の表で関係を整理してみましょう。
| コマンド | NODE_ENV | モード |
|:-|:-|:-|
| vite build | production | production |
| vite build --mode development | production | development |
| NODE_ENV=development vite build | development | production |
| NODE_ENV=development vite build --mode development | development | development |

この違いは`import.meta.env`の値にも反映されます。

#### NODE_ENVとPROD/DIVの関係
| NODE_ENV | import.meta.env.PROD | import.meta.env.DEV |
|:-|:-|:-|
| NODE_ENV=production | true | false |
| NODE_ENV=development	 | false | true |
| NODE_ENV=other | false | true |

#### --modeとMODEの関係
| コマンド | import.meta.env.MODE |
|:-|:-|
| --mode production | production |
| --mode development | development |
| --mode staging | staging |

### HTMLでの環境変数の利用
環境変数はHTMLファイル内でも利用できます。
```html
<h1>Welcome to %VITE_APP_TITLE%</h1>
```
ただし、存在しない環境変数は置換されず、そのまま残ります。

### TypeScriptでの型定義
TypeScriptを使っている場合、環境変数の型定義を行うと便利です。

`vite-env.d.ts`を以下のように作成します。

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

interface ImportMetaEnv {
  readonly VITE_API_URL: string
  readonly VITE_APP_TITLE: string
  readonly VITE_FEATURE_FLAG: string
  // 他の環境変数...
}

interface ImportMeta {
  readonly env: ImportMetaEnv
}
```
これにより、環境変数を使用する際に型チェックと自動補完が効くようになります。


## まとめ
Viteの環境変数とモードについて、基本的な使い方を確認しました。
適切に活用することで、開発環境と本番環境の切り替えがスムーズになり、より効率的で安全な開発が可能になります。