✂️

Next.jsをサブディレクトリで運用する

2024/01/11に公開

すでに何らかのアプリケーションが運用されているドメインに、新たに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 で切るのは理にかなっている
  • 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と同一のドメインで共存させることができます。

ムーザルちゃんねる

Discussion