T-CREATOR

Next.js のバンドルサイズを可視化する@next/bundle-analyzer の紹介

Next.js のバンドルサイズを可視化する@next/bundle-analyzer の紹介

Next.js のバンドルサイズを可視化する@next/bundle-analyzer の紹介

はじめに

最近ブログを作り直したのですが、その際@next/bundle-analyzerを使用してバンドルサイズを可視化することで何かしらの改善のアプローチを考えられないかと思い調査しました。

この記事ではその内容や使ってみた感想などを紹介させていただきたいと思います。

@next/bundle-analyzer

@next/bundle-analyzerは、Next.js プロジェクトのバンドルサイズを分析し、可視化するためのツールです。
ビルドプロセス中に生成されたバンドルのサイズ分布を詳細に表示します。

これにより、どのファイルがどれくらいのサイズかを視覚的に確認できるため、大きなサイズのモジュールやライブラリを特定しやすくなります。

また、このライブラリは内部的にwebpack-bundle-analyzerを利用していて
Next.js 用に利用しやすくカスタマイズされてものとなります。

使い方

環境情報

  • macOS 14.2.1 23C71
  • node v20.10.0
  • yarn 1.22.19

公式ページ

NPM @next/bundle-analyzer

インストール方法

zsh$ yarn add --D @next/bundle-analyzer

執筆時にインストールしたバージョン

zsh$  yarn list --pattern @next/bundle-analyzer
yarn list v1.22.19
└─ @next/bundle-analyzer@14.1.0

基本的な設定

next.config.jsまたはnext.config.ejsファイルを以下のように編集して、@next/bundle-analyzerを設定します。
ここではANALYZEという環境変数が渡ってきた場合のみbundle-analyzerが動くように設定しています。

javascript// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer');
const nextConfig = {};
module.exports =
  process.env.ANALYZE === 'true'
    ? withBundleAnalyzer({
        enabled: true, // bundle-analyzerを有効にする設定
        openAnalyzer: true, // ブラウザを表示する設定
      })(nextConfig)
    : nextConfig;

環境変数の渡し方は任意ですがここでは、package.jsonnpm-scriptsbundle-analyzer実行用のコマンドを追加しています。
本番用のコマンドと分けることで、本番ビルト時には実行させないようにすることができます。

json"scripts": {
  "build": "yarn build", // 本番用
  "build:bundle-analyzer": "ANALYZE=true yarn build", // 実行用
}

実行

ここでは Next.js アプリケーションのプロジェクトディレクトリで実行しています。

zsh$ yarn build:bundle-analyzer

実行するとブラウザが開き以下の 3 つのファイルが生成さます。
それぞれがなんなのかについて軽く触れてみます。

bundle-analyzerの実行時アプトプットされたファイル | client.html

client.html

client.html は、クライアントサイドで実行される JavaScript バンドルの可視化を提供します。
これには、ブラウザで直接実行されるページの JavaScript、クライアントサイドのライブラリ、フレームワークのコードが含まれます。

このファイルを使用する主な目的は、フロントエンドのパフォーマンス最適化です。JavaScript のサイズを減らすことで、ページの読み込み速度を向上させるべく要因を探します。

nodejs.html

server.html は、サーバーサイドで実行される JavaScript バンドルの可視化を提供します。
Next.js では、サーバーサイドレンダリング(SSR)または静的サイト生成(SSG)に使用されるコードが含まれます。

サーバーサイドのバンドルサイズを最適化することで、サーバーの応答時間を改善し、SSR や SSG のパフォーマンスを向上させます。この最適化により、サーバーの負荷を軽減し、より高速なページレンダリングを実現できます。

edge.html

edge.html は、Edge サイドで実行される JavaScript バンドルの可視化を提供します。
Next.js 12 以降、Middleware や Edge Functions など、CDN エッジサーバー上で実行されるコードに対応しています。

Edge サイドのコード最適化は、グローバルな CDN を通じて提供されるアプリケーションのパフォーマンスと拡張性を向上させることを目的としています。エッジコンピューティングを活用することで、ユーザーに近い場所でコードを実行し、レイテンシーを最小限に抑えることができます。

生成された HTML ファイルの見方

生成された HTML ファイルをどう確認するかについても簡単に触れます。

各ブロック

レポートに表示される各ブロックは、プロジェクト内のファイルや依存関係のモジュールを表します。ブロックにカーソルを合わせると、そのファイルやモジュールの正確なパスが表示されます。
これにより、どのファイルがバンドルサイズに大きく影響しているかを特定できます。

各ブロックの大きさ

ブロックの大きさは、そのファイルやモジュールがバンドル全体に占めるサイズの割合を表します。大きなブロックは、バンドルサイズに大きく影響しているファイルやモジュールを示し、これらは最適化の主なターゲットとなります。

色の意味合い

ブロックの色は、ファイルやモジュールの種類や所属するライブラリを表します。たとえば、異なる色は異なるライブラリやフレームワーク、プロジェクト内のカスタムコードなどを区別するために使われます。色による分類は、どのライブラリやフレームワークがバンドルサイズを大きくしているかを視覚的に識別するのに役立ちます。

  • 青色: 一般的には JavaScript ファイルを表します。
  • 緑色: CSS ファイルやスタイル関連のモジュールを指すことが多いです。
  • 灰色: サードパーティのライブラリやモジュール。
  • 赤色やオレンジ色: 大きなファイルや最適化が必要なファイルを警告として示すことがあります。

指標の種別

TreeMapSize でフィルタリングできる指標の種別についても触れてみます。

Stat

Stat は、ファイルがファイルシステムに保存される前の、圧縮や最適化を施されていない「生」のサイズを指します。これは、ソースコードがトランスパイル(例: TypeScript から JavaScript への変換)された後や、画像が Base64 でエンコードされる前のサイズですが、圧縮はまだ適用されていません。このサイズは、開発者が実際に書いたコードや追加したリソースの量を反映しています。

Parsed

Parsed は、ブラウザがファイルを解析して実行する準備をするために必要なサイズです。これは、ファイルが圧縮されていない状態で、必要な依存関係が解決され、モジュールが結合された後のサイズを指します。具体的には、Webpack などのビルドツールによってモジュールがバンドルされた後のサイズですが、まだ Gzip などの圧縮は適用されていません。このサイズは、実際にブラウザが解析するコードの量を示しており、パフォーマンスの最適化を行う際の重要な指標となります。

Gzipped

Gzipped は、ファイルが Gzip アルゴリズムによって圧縮された後のサイズを指します。これは、Web サーバーからクライアント(ブラウザ)へ送信される実際のファイルサイズであり、ネットワークを介して転送されるデータの量を減らすために最も一般的に使用される圧縮方法の一つです。Gzip 圧縮は、テキストベースのファイル(HTML、CSS、JavaScript など)に特に効果的であり、ファイルサイズを大幅に削減することができます。このサイズは、実際の転送コストとロード時間に直接影響を与えるため、Web パフォーマンスを評価する上で最も重要な指標の一つとなります。

どの指標を見ていくか

合計サイズを少なくしていくというこことがパフォーマンス改善として求められますがこの中のどの指標を見てくかについて紹介します。 ここで見ていくべき指標は、「Gzipped」サイズを基準として考えるべきといわれています。
この理由は、Web ページのパフォーマンス改善に関するベストプラクティスや指標を提供する際、通常はネットワーク経由で転送されるデータ量に焦点を当てるためです。
ただし、この値はあくまで目安であり、アプリケーションの内容やユーザーのインターネット速度によって最適なサイズは異なります。

実際の改善に向けた取り組み

詳細なパフォーマンスの改善に関しては今後改めて調査し別で記事にしたいと考えております。

一般的な改善のケース

ここではいくつかの一般的なケースについて紹介させていただきます。

大きなライブラリの置き換え

ライブラリのサイズがボトルネックとなっている場合、別のライブラリを検討する機会となるかもしれません。
moment.js を date-fns や dayjs に置き換えたりなどの話を聞きますが、これらのライブラリはモジュール単位でインポートできるため、必要な機能のみを読み込むことが可能です。こういった観点で代替し前後比較することでバンドルサイズを減らしていくことができます。

不要なポリフィルの削除

Next.js プロジェクトでは、babel.config.js を使用して Babel の設定をカスタマイズできます。特に、@babel/preset-env プリセットの targets オプションを活用することで、サポートするブラウザのバージョンを指定し、プロジェクトに必要なポリフィルのみを含めることが可能になります。
これにより、バンドルサイズを減らすことができ、アプリケーションのパフォーマンスを向上させることができます。useBuiltIns: 'usage'オプションを設定することで、コード内で実際に使用されている JavaScript の新機能に必要なポリフィルのみが含まれるようになり、不必要なポリフィルがバンドルから除外されます。

コードスプリッティングの適用

初期ロード時に不必要なコードが多く含まれている場合、コードスプリッティングの適用が有効です。
Next.js では、React.lazy と Suspense、または next/dynamic を使用することで、ページやコンポーネントを必要に応じて遅延読み込みできます。
これにより、初期ロードに必要な JavaScript の量を減らし、ページの表示速度を向上させることが可能です。特に、ユーザーが直接アクセスしない機能やページに対してこの技術を適用することで、パフォーマンスの大幅な改善が期待できます。

調べたり使ってみた所感

パフォーマンス改善を行うにあたり必須のライブラリであると思いました。その上で 2 点雑に感じたことをお伝えします。

パフォーマンスに影響する実装の観点を養う

変更を加えた際にbundle-analyzer実行し日頃チェックしていくことで実装における影響がどれだけなのかを理解する観点を養うことができるのではと思いました。

ライブラリの選定

新なライブラリ導入にあたり、それぞれ入れて bundle-analyzerを実行した結果を比較することでパフォーマンス観点でどちらが最適なのかを選ぶ選定基準として利用できるのではと思いました。

まとめ

Next.js プロジェクトのバンドルサイズを可視化し、パフォーマンス改善のアプローチを見つけ出すためのライブラリ@next/bundle-analyzer について紹介させていただきました。
このツールは、ビルドプロセス中に生成されたバンドルのサイズ分布を詳細に表示し、大きなサイズのモジュールやライブラリを特定しやすくすることができます。

これらを踏まえ、パフォーマンス改善に不可欠なツールであり、今後も積極的に活用していく価値があると考えております。

参考資料

記事Article

もっと見る