【Next.js】実行時の環境変数をクライアントで使いたい(NEXT_PUBLIC_不使用)
こんにちは、フリーランスエンジニアの太田雅昭です。
2024/07/25追記
下記の方法は、結局うまくいきませんでした。正常に動作すると思っていたら、急に不具合が出たりします。Next.jsは子コンポーネントからレンダリングされるため、グローバルに変数を渡すにはやはりProviderを使うしかないのかもしれません。
Next.jsの環境変数問題
Next.jsはサーバーサイドとクライアントサイドの両方を、同時に扱うことができます。そのため環境変数などに入れる機密情報は、扱いが難しくなりがちです。そのため、Next.jsでは環境変数は基本的にはクライアントには流しません。唯一、以下の形式の場合のみ、クライアントに流します。
NEXT_PUBLIC_XXX
上記のように、NEXT_PUBLIC_プレフィックスのついた環境変数は、自動的にクライアントサイドに流されます。
NEXT_PUBLIC_はビルド時固定
ここで注意すべき点がありまして、NEXT_PUBLIC_のついた環境変数はビルド時に固定化されます。そのため通常の環境変数のように扱うと、痛い目を見ることになります。
またビルド時に固定されるため、実行時に環境変数を変更しても反映されません。何度環境変数をいじろうが、ビルド時の値が帰ってくることになります。そのためdevelopment, staging, productionで使い分けするには、それぞれのビルドを作成しなければいけないことになります。
実行時の環境変数もクライアントで使いたい
当然、実行時の環境変数をクライアント側で使いたいといった時があります。もちろん、セキュリティを考慮して機密情報を流すわけにはいきませんが、せめてどの環境で実行しているかの情報ぐらいは渡してもいいのではないでしょうか。
方法としては色々あります。フックを使ったり、専用のエンドポイントを作ったりなどです。ただそれぞれ短所があります。フックは単純な関数内では使えませんし、エンドポイントは負荷が増えます。
そのため、以下のようにしてみました。サーバー側でmetaタグを使って埋め込んでいます。
// clientAndServer.ts
export const APP_ENV_META_NAME = 'app-env';
export function getAppEnv() {
if (isServer()) {
return process.env.APP_ENV;
}
const dom = document.querySelector(`meta[name="${APP_ENV_META_NAME}"]`);
return dom?.getAttribute('content');
}
export function isServer() {
return typeof window === 'undefined';
}
// layout.tsx
...
<meta name={APP_ENV_META_NAME} content={process.env.APP_ENV}></meta>
...
うーん、美しい。
小話
最近Youtubeに飽きてきました。前はよく見てたのですが、最近はあまり見ないです。なんででしょう。世の中の楽しみはやっぱり、酒とコーヒーでしょうか。