こんにちは。先日ブログ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ぜひお伝え下さい。
ありがとうございました。