こんにちは。先日ブログSaaSアプリの報告記事(Qiita)を挙げてから、
マイナーチェンジやバグ修正なりで、時々Next.jsのリビルド・再ビルドを行う必要性が出てきました。
件のNext.jsアプリはConoha VPSの2GBメモリ・3コアCPUのプランで動かしています。
(※ 実際、この程度のアプリだと、動かすだけならこれほどのスペックはあまり要りませんが、
僕の場合VPS上でVSCodeを立ち上げデバッグしてしまうので、割りと1.8GBくらいまで行ってしまいます)
このスペックでNext.jsのビルド npx next build
を行うと、
$ time NEXT_PUBLIC_APP_MODE=production NEXT_PUBLIC_APP_DIST=.next/prod.tmp npm run build
real 1m13.301s
user 2m11.505s
sys 0m6.562s
1分以上も掛かってしまい、
これを、next start
を一度停止して行っていると、その間に訪問したユーザに不便となってしまいます。
そのため、他のディレクトリに一度ビルドをして、それをコピー/名前変更して、再度next start
を行えば、サービスのダウンタイムが最小に抑えられます。
ビルド先のディレクトリを変更するには、distDir
を指定します。
next.config.js
に以下の例のようにdistDir
を指定し、
コマンドラインからNEXT_PUBLIC_APP_DIST
を渡して出力先ディレクトリを動的に変更できるようにします。
// ./next.config.js
..
const app__mode = process.env.NEXT_PUBLIC_APP_MODE === 'production' ? 'production' : 'development';
const app__dist = process.env.NEXT_PUBLIC_APP_DIST;
module.exports = withPWA({
pwa: {
..
},
distDir: app__dist || ( app__mode === "production" ? '.next/prod' : '.next/dev' ), // <-- 追加
..
})
ファイルを変更してリビルドしたい場合に、NEXT_PUBLIC_APP_DIST
に.next/prod.new
のように指定をします。
$ NEXT_PUBLIC_APP_MODE=production NEXT_PUBLIC_APP_DIST=.next/prod.new npm run build
ビルドが完了すると、以下のようなディレクトリ構造になります。
$ tree -L 1 .next
.next
├── dev
├── prod
└── prod.new
prod
ディレクトリをprod.old
に名前変更し、
prod.new
ディレクトリをprod
ディレクトリに名前変更します。
mv .next/{prod,prod.old}
mv .next/{prod.new,prod}
なお、上記の作業は素早く行わないと、Next.jsがprod
ディレクトリを作成してしまいます。
また、そのまま放置すると、アプリもコードが不完全なため不安定になります。
そのため、上記の作業を.shファイルなどからバッチ処理で行うか、一度next start
を停止してから行うとよいと思います。
上記の作業を完了すると、以下のようなディレクトリ構造になります。
$ tree -L 1 .next
.next
├── dev
├── prod
└── prod.old
この時点で、Next.jsサーバーを一度停止、再スタートさせます。
$ NEXT_PUBLIC_APP_MODE=production npx next start --port 3001
アプリが正常に動くか確認し、確認できれば完了です。
アプリがバグってしまったら、prod.old
ディレクトリをprod
に戻してロールバックを行います。
mv .next/{prod,prod.new}
mv .next/{prod.old,prod}
以上です。
PS. よいやり方の提案・間違い修正etcぜひお伝え下さい。
ありがとうございました。