😨

Next.js でブラウザ側(クライアントサイド)に公開した NEXT_PUBLIC_ な環境変数の注意点

2022/02/06に公開

NEXT_PUBLIC_ プレフィックスをつけておくだけでしょ?と思ってたらうまく読み取れずにハマったのでメモです

結論

環境変数の読み取り方も大事
クライアントサイドで環境変数を読み取るときは、回りくどい方法で環境変数を取得するのはやめて process.env.NEXT_PUBLIC_xxx 直打ちで取得するのがベター

まあふつーに読めば問題ないです

ブラウザに環境変数を公開する方法

ドキュメントにもある通り、NEXT_PUBLIC_ をつけるだけでブラウザ側に公開されます

In order to expose a variable to the browser you have to prefix the variable with NEXT_PUBLIC_

https://nextjs.org/docs/basic-features/environment-variables#exposing-environment-variables-to-the-browser

何にハマったか

以下のような便利関数を経由して環境変数を取得していました

type NameToType = {
  readonly ENV: 'production' | 'staging' | 'development' | 'test';
  ...
};

export function getEnv<Env extends keyof NameToType>(name: Env): NameToType[Env];
export function getEnv(name: keyof NameToType): NameToType[keyof NameToType] {
  const val = process.env[name];
  if (!val) {
    throw new Error(`Cannot find environmental variable: ${name}`);
  }

  return val;
}

この関数を使うと環境変数の名前によって返り値の型が推論されるので便利なのですが

この関数を使って .env ファイルで定義した NEXT_PUBLIC_ プレフィックスな環境変数をブラウザから取得しようとしてもエラーになってしまいます

原因

こちらは next.config.js の env フィールドについての説明ですが、次のように書いてあります

Next.js will replace process.env.customKey with 'my-value' at build time. Trying to destructure process.env variables won't work due to the nature of webpack DefinePlugin.

https://nextjs.org/docs/api-reference/next.config.js/environment-variables

Webpack の DefinePlugin を使って単に process.env.xxx な文字列を環境変数の値に置換しているだけので、destructure してると上手く動かないよ、とのことです

NEXT_PUBLIC_ プレフィックス付き環境変数についてもおそらく同様の方法で展開されているので同じ制約がかかるという訳です

上で紹介した getEnv 関数のように process.env['NEXT_PUBLIC_xxx'] とアクセスしたり const { NEXT_PUBLIC_xxx } = process.env と分割代入していたりするとうまく動かないわけですね

getEnv で取得するのはやめて、直接 process.env.NEXT_PUBLIC_xxx と取得するようにしたことで上手く動くようになりました

まとめ

クライアントサイドで環境変数を読み取るときは、回りくどい方法で環境変数を取得するのはやめて process.env.NEXT_PUBLIC_xxx 直打ちで取得するのがベター

ブラウザ側で process.env オブジェクトが作られてそこに NEXT_PUBLIC_ プレフィックスな環境変数がいい感じに生えてくるような挙動と思っていたので1時間ぐらいハマっちゃいました

Discussion