Next.js でSSR,SSGのみプライベートネットワークの通信を使うには環境変数で host 指定がおすすめ
Next.js も API も同一のネットワーク上にサーバーがある場合、SSGやSSRをするときにAPIとの通信はプライベートネットワークを使いたくなることがあります。
Ajax や fetch 使用時の host を分ければいいのですが、Next.js が提供する機構で極力シンプルに要件を満たしてみようと思います。
結論
結論はこの記事のタイトルのとおりクライアントサイドとサーバーサイド向けの host 指定する環境変数を容易するのがアプリケーションコードへの影響が少なくおすすめです。.env
ファイルに下記のような環境変数を用意します(NEXT_PUBLIC_
接頭辞の有無が重要です)
- サーバーサイド用ホスト指定 API_SERVER_HOST
- クライアントサイド用ホスト指定 NEXT_PUBLIC_API_SERVER_HOST
Axios での使用例
const instance = axios.create({
baseURL: `https://${API_SERVER_HOST||NEXT_PUBLIC_API_SERVER_HOST}/api/v1`
});
これは NEXT_PUBLIC_
接頭辞がついた環境変数のみビルド時にクライアントサイドのコードに環境変数が展開される Next.js の機構を利用しています。
それ以外のアプローチ
前述の結論で分かる方はこの後はとくに読む必要がないかもしれませんが解説していきます。
考えられるアプローチは下記になると思います。
- サーバーで実行するAPIコールを特定して処理を変える
- 実行環境に応じて使用する host を変更する
サーバーで実行するAPIコールを特定して処理を変える
Next.js の設計にのっている場合 SSR, SSG 時にサーバーサイドで API コールが実行されるのは下記に集約できるはずです。
- getServerSideProps
- getStaticProps
- getStaticPath
なので、この内部で使われる Ajax や fetch では host がプライベートネットワークになるように処理を変えれば対応できます。
しかし、この方法だとAPIコールをする場合に常にサーバーサイドでの実行かクライアントサイドでの実行かを意識しなければならず、開発規模が大きくなってきたりチームメンバーが増えてくるとストレスになること間違いなしです。
(冷静に考えれば当たり前でも、ネットワーク要件でバタバタと改修することになると思いもよらないアプローチを取りそうになります。冷静さを欠いていて危なく採用しそうになりました。)
実行環境に応じて使用する host を変更する
Next.js 以前から SSR などで Isomorphic なコードを書いている方はこちらをすぐに思いつくでしょう。
window の有無などブラウザと node.js 環境の違いを起点に host 指定を変更すればOKです。
typeof window !== "undefined"
=> false // サーバーサイドの場合 window が存在しないので false が返る
Axios の場合、こんな感じで指定してあげることでアプリケーション内の全通信を一括でコントロールできます。
const instance = axios.create({
baseURL: `https://${typeof window !== "undefined" ? "example.com" : "example.internal"}/api/v1`
});
Next.js に限らず Node.js で SSR と CSR で通信を分けたいときはこうするのが意図もわかりやすく、設定一箇所で済むので見通しの良いコードになります。
環境変数の使用
実際のアプリケーション開発では本番環境やテスト環境、ローカル環境で API サーバーは別に用意することがほとんどです。
そうなると host はソースコード内に記述するわけにはいけません。そのため .env
ファイルなどで下記のように指定して環境変数から host の情報を渡す用にするのが一般的ではないでしょうか。
.env
ファイル
API_SERVER_HOST=example.com
INTERNAL_API_SERVER_HOST=example.internal
Axios の例
const { API_SERVER_HOST, INTERNAL_API_SERVER_HOST } = process.env
const instance = axios.create({
baseURL: `https://${typeof window !== "undefined" ? API_SERVER_HOST : INTERNAL_API_SERVER_HOST}/api/v1`
});
NEXT_PUBLIC_ 変数の利用
前述のとおり Next.js には NEXT_PUBLIC_
接頭辞をつけたものだけブラウザサイドの js に渡されるという機構があります。
- Exposing Environment Variables to the Browser
https://nextjs.org/docs/basic-features/environment-variables#exposing-environment-variables-to-the-browser
これを利用することで window の有無を確認せずとも環境変数の有無でサーバーサイドとクライアントサイドで利用する host の切り替えが可能になります。
API_SERVER_HOST=example.com
NEXT_PUBLIC_API_SERVER_HOST=example.internal
Axios の例
const API_SERVER_HOST = process.env.API_SERVER_HOST
const NEXT_PUBLIC_API_SERVER_HOST = process.env.NEXT_PUBLIC_API_SERVER_HOST
const instance = axios.create({
baseURL: `https://${NEXT_PUBLIC_API_SERVER_HOST || API_SERVER_HOST}/api/v1`
});
まとめ
今回の手法は普段お仕事を手伝ってもらっている MATSUKAZE. 及川さんに助言いただきました。及川さんありがとうございます!
NEXT_PUBLIC_
の挙動を知っていてもその使いみちやパターンを理解できていないと無駄なコードを書いてしまうなーと実感したので記事にまとめてみました。
今回は粒度の小さな Tips でしたが、これからもフレームワークやライブラリの便利な機能とそれを適切に使う方法を学んでいき共有していきます。
開発のお悩み、フロントエンドから解決しませんか?
あなたのチームのお悩みはなんですか?
「バックエンドエンジニアにフロントエンドまで任せてしまっている」
「デザイナーに主業務以外も任せてしまっている」
「すべての手が足りず細かいことまで手が回らない」
役割や領域を適切に捉えてカバーし、チーム全体の生産性と品質をアップするお手伝いをします。
フロントエンド開発に関わるお困りごとがあれば、まずは一度お気軽に Gaji-Labo にお声がけください。
オンラインでのヒアリングとフルリモートでのプロセス支援に対応しています。
リモートワーク対応のパートナーをお探しの場合もぜひ弊社にお問い合わせください!
お悩み相談はこちらから!