Next.jsをサブディレクトリで運用する
すでに何らかのアプリケーションが運用されているドメインに、新たにNext.jsアプリケーションを追加したい場合に特定のサブディレクトリ以下をNext.jsにすることができます。やり方は大きく2つあります。
A: 特定のサブディレクトリ以降をNext.jsにする
すでにRailsが動いていて、/nextjs以下はNext.jsで動かしたい例
B: 複数のサブディレクトリ以降をNext.jsにする
すでにRailsが動いていて、/foo,/bar,/hoge/bazをNext.jsで動かしたい例
2つのパターン違い
どちらも同じように見えますが、使い勝手や運用は若干異なります。
- A: 特定のサブディレクトリだけをNext.jsにする
- メリット
- 設定が単一になるのでリバースプロキシの変更頻度が低い
- デメリット
- URL構造で見たときに一つ余計なサブディレクトリがはさまる
- これはアプリケーション要件次第なのでメリットにもなる
- 例えばブログをNext.jsで作るのであれば
/blog
で切るのは理にかなっている
- URL構造で見たときに一つ余計なサブディレクトリがはさまる
- メリット
- B: 複数のサブディレクトリをNext.jsにする
- メリット
- アプリを気にせずURL構造の設計ができる
- デメリット
- 新しくエンドポイントを増やすたびにリバースプロキシの設定変更が必要
- Next.jsの
/public
ディレクトリのファイルに一工夫いる
- メリット
実現方法
今回はNginxを使いますが、おそらくAWS ALBなどの環境でも同様に実現ができると思います。また、A/Bどちらの方針もやることは大きく代わりません。多少の差分があるだけです。
サンプルコードは以下のリポジトリにあります。
nginxの設定
ローカルで動作確認ができるようにDockerでNginxの環境を作ります。
version: "3"
services:
nginx:
image: nginx:latest
ports:
- "8080:8080"
volumes:
- ./nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf
- ./html:/usr/share/nginx/html
Nginxの設定ファイルとHTMLをVolumesで上書きします。
default.conf
server {
listen 8080;
listen [::]:8080;
server_name localhost;
# 既存アプリケーション(例えばRailsなど)
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
# http://host.docker.internal:3000 はNext.jsが動いている前提
# パターンAの場合
location /nextjs {
proxy_pass http://host.docker.internal:3000;
}
# パターンBの場合
# /_next : Next.jsが出力する静的ファイルにアクセスできるようにする
# /_next_public : Next.jsのpublicディレクトリを参照するために(詳しくは後述)
# /foo, /bar, /hoge/baz : にマッチした場合はNext.jsへ
location ~ ^/(_next|_next_public|foo|bar|hoge\/baz) {
proxy_pass http://host.docker.internal:3000;
}
}
- 8080ポートでNginxを動かします
- 本番環境としてはは80ポートになると思います
- ホスト側に適当に
./html/index.html
ファイルを作ります- 既存アプリケーションのダミー
- '/' ディレクトリはNginxがホストする普通のHTMLファイルを返します
- 最初の図でいうRailsアプリ相当
- パターンAの場合
- '/nextjs' ディレクトリは3000ポートのNext.jsを参照します
- Next.jsはDockerではなくホストで動かすので
host.docker.internal
としています
- パターンBの場合
-
^/(_next|_next_public|foo|bar|hoge\/baz)
の正規表現でマッチさせたいパスを記述
-
これでNginxの設定は完了です。DockerでNginxコンテナを起動しておきます。
docker compose up -d
Next.jsの設定
パターンA : next.config.js
パターンAのみ場合のみ、Next.js側で設定しておくとちょっと楽になるかもしれないTips紹介です。
basePath
という設定をするとNext.jsのルートディレクトリを変更することができます。これをしなくても正常に動かすことができるので完全に好みですが、Next.jsのディレクトリ構成が1段減ってシンプルになるので管理はしやすくなります。
/** @type {import('next').NextConfig} */
const nextConfig = {
basePath: '/nextjs', // サブディレクトリ名
}
module.exports = nextConfig
basePath設定した場合の各種リンクパス
-
basePath
を指定している場合、リンクは自動で補完されます- つまり
/nextjs/sample
というURLに対してリンクをするには以下になります <Link href="/sample">sample page</Link>
- つまり
-
/public/
ディレクトリにある画像などのリンクだけは自動補完されないです<Image src="/nextjs/vercel.svg" />
パターンB : publicディレクトリ
パターンBではトップレベルを既存アプリに渡している関係上 /public
に配置された画像ファイルなどにはそのままではアクセスできません。そこで、一つ階層をほってリバースプロキシしてあげます。
-
/public/_next_public
ディレクトリを作成する- この中に
next.svg
などの画像ファイルを配置 - DOMからは
<img src="/_next_public/next.svg" />
と参照 - *)パス名がださいので適宜変更してください
- この中に
Next.jsを起動する
後は普通に npm run dev
して3000ポートでNext.jsを起動します。
すると以下のURLで既存のアプリとNext.jsと同一のドメインで共存させることができます。
- パターンAの場合
- http://localhost:8080/ : 既存アプリ
- http://localhost:8080/nextjs : Next.jsアプリ
- パターンBの場合
- http://localhost:8080/ : 既存アプリ
- http://localhost:8080/foo : Next.jsアプリ
- http://localhost:8080/bar : Next.jsアプリ
- http://localhost:8080/hoge/baz : Next.jsアプリ
Discussion