Next.js App Router 実行時環境変数の参照方法を考えたよ。
本記事では、Next.js アプリケーションにおいて「ビルド時」ではなく「実行時」に環境変数を参照する方法について解説します。特に、Client Component
から環境変数を扱いたい場合に焦点を当てます。
例えば、デプロイ先や環境(production、stagingなど)に合わせて設定を切り替える必要がある場合など、ビルド済みのコードに依存しない形で環境変数を読み込むニーズは少なくありません。
さっそくですが、基本的な実装例は以下のようになると思います。
-
Server Component で環境変数を取得:
Server Component
にてprocess.env
を介して実行時環境変数を取得する。 -
ContextProvider に環境変数を渡す:
取得した実行時環境変数をContextProvider
のvalue
に指定する。
そして、このように Client Component
から Context
の値を参照できるかと思います。
export const ClientComponent = () => {
const env = useEnvContext(); // Contextを利用するカスタムフック
return (
<div>
<h1>環境変数の確認!</h1>
<pre>{JSON.stringify(env, null, 2)}</pre>
...
しかし、hooks(useEnvContext
)が利用できない場面ではどう対応するべきか?
例えば、API リクエストを行う関数内で、API の baseURL
を実行時環境変数から参照したいケースを考えてみます。(引数で渡して解決する方法もありますが、ここでは考えないことにします)
つまり、hooks(useEnvContext)
が利用できないケースに対応する必要があります。
今回は window
オブジェクトから参照できるような機構を作り対応してみましょう。
実装例は以下になります。
export default function Layout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const env = getEnv();
return (
<html lang="ja">
<head>
<Script
id="runtimeEnv"
strategy="beforeInteractive"
>{`window.RUNTIME_ENV = ${JSON.stringify(env)}`}</Script>
</head>
<body>
{children}
</body>
</html>
);
}
Script
タグ内で window
オブジェクトに、パースした環境変数を格納しています。
また、一番最初に読み込む必要のある重要なスクリプトなので、beforeInteractive
属性を指定しております。
beforeInteractive
に関する説明は以下を参照してください。
注意点としては、検証ツールから閲覧可能な状態になってしまいますので、公開しても問題ない環境変数のみを格納しましょう。
getEnv
の実装例はこちらです。
ここで window
オブジェクトに格納したい環境変数を抽出しています。
server/client の両環境から同じ命名でアクセスできるようにする必要があるため注意しましょう。
(例えば、API_URL: process.env.BASE_URL
など書かないようにしましょう)
T3 Env を利用すると強力な型付が可能になりそうですね。
export const getEnv = () => {
noStore(); // unstable_noStore
return {
BASE_URL: process.env.BASE_URL,
};
};
そして、実行時環境変数を参照するための関数を作成します。
サーバ環境からは process.env
から、クライアント環境からは window
オブジェクトから値を参照することができます。
export const getRuntimeEnv = (
key: keyof ReturnType<typeof getEnv>
): string | undefined => {
const isBrowser = Boolean(typeof window !== "undefined");
if (isBrowser) {
return window["RUNTIME_ENV"]?.[key];
}
noStore(); // unstable_noStore
return process.env?.[key];
};
利用例はこちらです。
この api
を利用して、routeHandler
もしくは ClientComponent
から API通信処理を実装することができます。
export const api = axios.create({
baseURL: getRuntimeEnv("BASE_URL"),
headers: {
"Content-Type": "application/json",
},
...
});
以上。
本記事では、hooks
が利用できない環境において実行時環境変数を参照する方法例を紹介しました。
ご意見や改善点がありましたら、ぜひコメントなどでご指摘ください。
Discussion