どうも、インターンの手塚です。今回は、Next.jsのstandaloneという機能に焦点を当てた記事を書こうと思います。standalone機能がビルドサイズをどれだけ小さくするのかを確認してみましょう。
目次
standalone機能とは
// next.config.js
module.exports = {
output: 'standalone',
}
公式ドキュメントにもあるように、next.config.js
に上のように書くことでstandalone機能が有効になります。このモードが有効になった状態でビルドすると、.next
ディレクトリ下にstandalone
フォルダが作成されます。このフォルダの下には、node_modules
から、使用するファイルのみがコピーされ、さらにnext start
コマンドの代わりに使用できる最小限のserver.js
ファイルが生成されます。
要するに、自動的にstandalone
フォルダが作成され、その中に動作に必要な最小限のファイル群がコピーされるという便利な機能です。この機能によってビルドサイズを削減できます。
いざビルド
自分が個人的に運営しているブログを実際に2通りの方法でビルドして確認してみたいと思います。参考までに、ブログの依存関係は下の通りです。
// package.json
"dependencies": {
"autoprefixer": "^10.4.7",
"copy-webpack-plugin": "^11.0.0",
"gray-matter": "^4.0.3",
"markdown-it": "^13.0.1",
"markdown-it-anchor": "^8.6.4",
"markdown-it-container": "^3.0.0",
"markdown-it-emoji": "^2.0.2",
"markdown-it-prism": "^2.2.4",
"markdown-it-table-of-contents": "^0.6.0",
"next": "12.1.6",
"react": "18.1.0",
"react-dom": "18.1.0",
"write-file-webpack-plugin": "^4.5.1"
}
特に複雑でもない、Next.js製のよくある静的な個人ブログです。
standalone機能を無効にしてビルド
まずは、standalone機能を無効にした状態でビルドしてみます。
# Dockerfile
FROM node:16 AS builder
WORKDIR /app
COPY . .
RUN yarn install --frozen-lockfile --production=false
RUN yarn build
FROM node:16 AS runner
WORKDIR /app
COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY package.json ./
COPY yarn.lock ./
RUN yarn install --frozen-lockfile --production=true
CMD ["yarn", "start"]
# in package.json
# scripts": {
# "start": "next start",
# },
standalone機能を無効にしているので、本番用にビルドしたnode_module
をそのままビルドに含めます。
docker build -t not_standalone .
docker run -p 3000:3000 not_standalone
ビルドして、ブラウザからアクセスができることを確認します。
standalone機能を使用しない場合のイメージサイズは、2.09GBでした。
standalone機能を有効にしてビルド
続いて、standalone機能が有効な状態でビルドをしてみたいと思います。
# Dockerfile
FROM node:16 AS builder
WORKDIR /app
COPY . .
RUN yarn install --frozen-lockfile
RUN yarn build
FROM node:16 AS runner
WORKDIR /app
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/public ./standalone/
COPY --from=builder /app/.next/static ./standalone/.next/
CMD ["node", "server.js"]
公式のDockerfileを参考にしながらDockerfile
を作成します。standalone機能を有効にしているので、本番用にビルドしたnode_module
をビルドに含める必要がありません。
public
や.next/static
などの静的なファイルは通常CDNによって配布される想定なので、自動的にはstandalone
フォルダの下にはコピーされませんが、手動でこれらをstandalone/public
、standalone/.next/static
にコピーすることで、文字通りstandaloneフォルダの中のみでアプリを動作させることが可能になります。
docker build -t standalone .
docker run -p 3000:3000 standalone
ビルドして、ブラウザからアクセスができることを確認します。
standalone機能を有効にした時のイメージサイズは、956.74MBでした。
結果を比較
standalone機能が無効な状態だと: イメージのサイズが2.09GB。
standalone機能が有効な状態だと: イメージのサイズが956.74MB。
と大幅にビルドのサイズが小さくなっていることがわかりました。アプリが正常に動作するならビルドサイズは小さいに越したことはありませんので最高に嬉しいですね!
最後に
クラウドのコンテナレジストリサービスを使っている人は、イメージのサイズで料金が変わってきたりすることもあるかと思います。DockerとNext.jsを用いてアプリをデプロイしている人は、ぜひstandalone機能を活用してみてください!!!