Menu

メモリ使用量を最適化する

アプリケーションが成長し、機能が豊富になるにつれて、ローカル開発時や本番ビルド作成時により多くのリソースが必要になる場合があります。

Next.jsでメモリを最適化し、一般的なメモリの問題に対処するためのいくつかの戦略とテクニックを探していきましょう。

依存関係の数を削減する

大量の依存関係を持つアプリケーションはより多くのメモリを使用します。

Bundle Analyzerを使用すると、アプリケーション内の大きな依存関係を調査でき、パフォーマンスとメモリ使用量を改善するために削除できる可能性のある依存関係を特定できます。

experimental.webpackMemoryOptimizationsを試す

v15.0.0以降、next.config.jsファイルにexperimental.webpackMemoryOptimizations: trueを追加して、Webpackの動作を変更し、最大メモリ使用量を削減できます。ただし、コンパイル時間がわずかに増加する可能性があります。

補足:この機能は現在、より多くのプロジェクトでテストするための実験的機能ですが、低リスクと見なされています。

--experimental-debug-memory-usagenext buildを実行する

14.2.0以降、next build --experimental-debug-memory-usageを実行して、ビルドをモードで実行できます。このモードでは、Next.jsはビルド全体を通じてメモリ使用量に関する情報を継続的に出力します。ヒープ使用量やガベージコレクション統計などが表示されます。メモリ使用量が設定されたリミットに近づくと、ヒープスナップショットも自動的に取得されます。

補足:この機能はWebpack build worker オプションと互換性がありません。カスタムwebpack設定がない限り、自動的に有効になります。

ヒーププロファイルを記録する

メモリの問題を探すために、Node.jsからヒーププロファイルを記録し、Chrome DevToolsで読み込むことで、メモリリークの潜在的なソースを特定できます。

ターミナルで、Next.jsビルドを開始する際にNode.jsに--heap-profフラグを渡します:

node --heap-prof node_modules/next/dist/bin/next build

ビルドの終了時に、Node.jsによって.heapprofileファイルが作成されます。

Chrome DevToolsで、Memory タブを開き、「Load Profile」ボタンをクリックしてファイルを視覚化できます。

ヒープのスナップショットを分析する

インスペクターツールを使用して、アプリケーションのメモリ使用量を分析できます。

next buildまたはnext devコマンドを実行する際、コマンドの先頭にNODE_OPTIONS=--inspectを追加します。これにより、インスペクターエージェントがデフォルトポートで公開されます。 ユーザーコードが実行される前に中断したい場合は、代わりに--inspect-brkを渡すことができます。プロセスが実行中の場合、Chrome DevToolsなどのツールを使用してデバッグポートに接続し、ヒープのスナップショットを記録・分析して、どのメモリが保持されているかを確認できます。

14.2.0以降、--experimental-debug-memory-usageフラグを使用してnext buildを実行することで、ヒープスナップショットの取得が簡単になります。

このモードで実行中の場合、いつでもSIGUSR2シグナルをプロセスに送信でき、プロセスはヒープスナップショットを取得します。

ヒープスナップショットはNext.jsアプリケーションのプロジェクトルートに保存され、Chrome DevToolsなどのヒープアナライザーで読み込んで、どのメモリが保持されているかを確認できます。このモードはまだWebpack build workersと互換性がありません。

詳細については、ヒープスナップショットを記録・分析する方法を参照してください。

Webpack build worker

Webpack build workerでは、Webpack コンパイレーションを別のNode.jsワーカーの内部で実行できます。これにより、ビルド中のアプリケーションのメモリ使用量が削減されます。

v14.1.0以降、アプリケーションがカスタムWebpack設定を持たない場合、このオプションはデフォルトで有効になります。

Next.jsの古いバージョンを使用している場合、またはカスタムWebpack設定がある場合、next.config.js内でexperimental.webpackBuildWorker: trueを設定して、このオプションを有効にできます。

補足:この機能は、すべてのカスタムWebpackプラグインと互換性がない場合があります。

Webpackキャッシュを無効にする

Webpackキャッシュは、生成されたWebpackモジュールをメモリおよび/またはディスクに保存し、ビルド速度を改善します。これはパフォーマンスに役立ちますが、キャッシュされたデータを保存するために、アプリケーションのメモリ使用量も増加します。

この動作を無効にするには、アプリケーションにカスタムWebpack設定を追加します:

next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (
    config,
    { buildId, dev, isServer, defaultLoaders, nextRuntime, webpack }
  ) => {
    if (config.cache && !dev) {
      config.cache = Object.freeze({
        type: 'memory',
      })
    }
    // 重要:修正されたconfigを返します
    return config
  },
}
 
export default nextConfig

静的分析を無効にする

型チェックは、特に大規模なプロジェクトでは、多くのメモリを必要とする場合があります。 ただし、ほとんどのプロジェクトには、これらのタスクを既に処理する専用のCI ランナーがあります。 ビルドが「Running TypeScript」ステップ中にメモリ不足の問題を引き起こす場合、ビルド中にこのタスクを無効にできます:

next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  typescript: {
    // !! 警告 !!
    // プロジェクトに型エラーがある場合でも、本番ビルドが正常に完了することを危険な状態で許可します。
    // !! 警告 !!
    ignoreBuildErrors: true,
  },
}
 
export default nextConfig

型エラーが原因で不正なデプロイが発生する可能性があることに注意してください。 静的分析が完了した後に、ビルドを本番環境に昇格させることを強くお勧めします。 Vercelにデプロイする場合、ステージングデプロイメントのガイドを確認して、カスタムタスクが成功した後にビルドを本番環境に昇格させる方法を学ぶことができます。

ソースマップを無効にする

ソースマップの生成は、ビルドプロセス中に追加のメモリを消費します。

Next.js設定にproductionBrowserSourceMaps: falseexperimental.serverSourceMaps: falseを追加することで、ソースマップ生成を無効にできます。

cacheComponents機能を使用する場合、Next.jsはnext buildのprerender フェーズ中にデフォルトでソースマップを使用します。 そのフェーズ中に一貫してメモリの問題が発生する場合(「Generating static pages」の後)、 Next.js設定にenablePrerenderSourceMaps: falseを追加して、そのフェーズでソースマップを無効にすることができます。

補足:一部のプラグインはソースマップをオンにする可能性があり、無効にするためにカスタム設定が必要な場合があります。

Edge のメモリの問題

Next.js v14.1.3はEdge runtime使用時のメモリの問題を修正しました。このバージョン(またはそれ以降)に更新して、問題が解決するかどうか確認してください。

エントリのプリロード

Next.jsサーバーが起動すると、各ページのJavaScriptモジュールをメモリにプリロードします。リクエスト時ではなく、起動時にプリロードします。

この最適化により、初期メモリフットプリントが大きくなる代わりに、より高速な応答時間が実現されます。

この最適化を無効にするには、experimental.preloadEntriesOnStartフラグをfalseに設定します。

next.config.ts
TypeScript
import type { NextConfig } from 'next'
 
const config: NextConfig = {
  experimental: {
    preloadEntriesOnStart: false,
  },
}
 
export default config

Next.jsはこれらのJavaScriptモジュールをアンロードしないため、この最適化が無効な場合でも、すべてのページが最終的にリクエストされた場合、Next.jsサーバーのメモリフットプリントは結果的に同じになります。