📘

【Next.js】Static Exportsの設定変更後にnext startが起動しない問題とその解決方法

2024/04/06に公開

Next.jsで静的ファイル(HTML, CSS, JavaScriptなど)を出力する場合に使用するStatic Exports機能ですが、v13.3で使用方法に変更がありました。
そこで、実際に変更してみたところ、変更後にnext startコマンドでアプリケーションが起動できなくなってしまったので解決方法を記事にしてみました。

Static Exportsの変更点

まず、Static Exportsの変更点について。

変更前
next exportコマンドを実行することで静的ファイルが出力されていましたが、このコマンドはv13.3から非推奨となり、v14で削除されています。

package.json
"build": "next build && next export"

変更後
v13.3からはnext.config.jsoutput: 'export'を設定する仕様に変更されています。

next.config.js
const nextConfig = {
  output: 'export',
}

https://nextjs.org/docs/app/building-your-application/deploying/static-exports

変更後にnext startで起動できなくなった

next.config.jsoutput: 'export'を設定して、next startでアプリケーションを起動しようとしたところ下記のエラーが発生しました。

shell
Error: "next start" does not work with "output: export" configuration. Use "npx serve@latest out" instead

どうやらoutput: "export"を有効にした状態ではnext startは使えないみたいです。
https://github.com/vercel/next.js/blob/acaf642fbdffef860e0fdf334046c7cab4af65b4/packages/next/src/server/next.ts#L227-L229
ちなみにnext devでは変更前と変わらず起動できました。(詳細は別のセクションに記載)

解決方法

まずは解決方法について。
エラーになった原因については後ほど説明します。

エラーメッセージにもUse "npx serve@latest out" insteadと記載されているようにserveを使うことで解決できます。

shell
yarn add -D serve
package.json
  "scripts": {
    "dev": "next dev",
    "build": "next build",
-   "start": "next start",
+   "start": "serve out",
    "lint": "next lint"
  },

serve outとしてserveで静的なファイルサーバーを立ててから、ビルド済みの静的ファイルが格納されているoutディレクトリをホスティングします。
serveをパッケージ管理しない場合は"start": "npx serve out"に書き換えてください。

http-serverなどの他の静的ファイルサーバーを使っても解決できますが、serveはVercelによって開発されたツールであり、Next.jsもVercelが開発しているため、Next.jsの静的ファイルを扱う際の特性に適していると言えます。

また、serveだとコードもより簡潔に書くことができます。

package.json
// http-server
"start": "http-server out -p 8000"
// serve
"start": "serve out"

next startで起動できなくなってしまった原因について

next startで起動できなくなってしまった原因としては、Static Exportsの設定変更による影響があげられます。

output: "export"が設定されている場合

  • 静的ファイルの出力: next build コマンドを実行すると、静的ファイル(HTML, CSS, JavaScriptなど)がoutディレクトリに出力されます。これらのファイルは動的な処理を必要とせず、そのままウェブサーバー上に提供できます。
  • 静的ファイルの公開: outディレクトリに生成された静的ファイルは、静的ファイルサーバー上に公開する必要があります。そのため、servehttp-serverのような静的ファイルサーバーが必要になります。

output: "export"が設定されていない場合

  • ビルドされたアプリケーションの出力: next build コマンドを実行すると、ビルドされたアプリケーションの成果物が.nextディレクトリに出力されます。こちらは静的ファイルだけでなく、SSRやAPIルートなど、Next.jsの動的機能をサポートするためのファイル群も含まれます。
  • アプリケーションの起動: ビルドされたアプリケーションは.nextディレクトリに出力され、next startコマンドによってproduction modeで起動されます。このnext startコマンドによって、内部でNode.jsサーバーを起動し、SSRやAPIルートへのリクエスト処理など、Next.jsの全機能を利用可能な状態にします。

つまり、output: "export"が設定されている場合は、outディレクトリに出力された静的ファイルを静的ファイルサーバー上に公開する必要があります。
この作業が抜けていたため、next startを実行した際にエラーになっていました。

next dev では起動できる理由

next startnext dev は、サーバー起動時の目的が異なります。
next startコマンドは、ビルド済みのNext.jsアプリケーションをproduction modeで起動するのに対し、next devコマンドはdevelopment modeでアプリケーションを起動します。
development modeでは、Next.jsはSSRやSSG、APIルートなどの開発中に利用される全ての機能を活用できるようにします。
これには、リアルタイムのホットリローディングやエラーメッセージの表示など、開発を効率化するための機能が含まれています。

そのため、output: "export"が設定された場合でも、next dev は静的サイトを生成するのではなく、直接Next.jsのサーバー処理を通じてページを動的にレンダリングします。
したがって、output: "export"設定による変更はnext buildnext startに影響しますが、開発プロセスをサポートするnext devの動作には影響しません。

まとめ

Static Exports機能の変更によって、next startが起動できなくなったことをきっかけに、Next.jsの仕様について改めて理解を深めることができました。
普段の業務などでは問題なく使いこなせてはいるものの、Next.jsの仕様について深堀りしていくと、development modeproduction modeの違いであったり、理解できていなかった部分も多くあるなと感じました。
そのため、今後は定期的にドキュメントを読み返すなどして、さらに理解を深めていけたらと思っています。

記事中に認識が間違っているところがありましたら、コメントでご指摘いただけますと幸いです。

Discussion