tree-shaking について
JavaScript 開発者向けに、バンドル時に未使用コードを除去してサイズを抑える方法を解説します。ES モジュールのインポートや副作用、その死コード除去への影響を扱います。
主な機能
- 01バンドル時に未使用コードを除去
- 02ES2015 の import/export 構文を使用
- 03名前付きインポートを優先
- 04適切な場合に副作用なしと指定
- 05副作用が除去に与える影響を解説
活用シーン
- 01JavaScript バンドルのサイズ削減
- 02未使用の依存コードの同梱を回避
- 03ページのダウンロードと解析を改善
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ patternsdev/ skills --skill tree-shakingインストール後、Claude Code で/tree-shakingを入力して読み込まれたか確認します。
詳細
Tree Shaking
アプリケーション内でどこにも使われていないコードが、バンドルに追加されることがあります。このような不要なコードは、バンドルのサイズを減らし、余分なデータの読み込みを防ぐために取り除けます。バンドルに追加する前に不要なコードを取り除く処理を、ツリーシェイキングと呼びます。
使用する場面
- バンドルに、インポートしたモジュールの未使用コードが含まれている場合に使用します
- JavaScript バンドルを軽量に保ち、読み込みパフォーマンスを向上させるのに役立ちます
手順
- ES2015 の
import/export構文を使用します。ツリーシェイキングできるのは ES モジュールのみです - 効果的なツリーシェイキングを可能にするため、モジュール全体をインポートするのではなく、名前付きインポートを使用します
- 適切な場合は、
package.jsonでパッケージに副作用がないことを指定します - 副作用のあるモジュールは安全にツリーシェイキングできないことに注意してください
詳細
概念
ツリーシェイキングは、最終的な JavaScript バンドルから、決して使われないコードを取り除くことを目的としています。適切に行えば、JavaScript バンドルのサイズを減らし、ダウンロードや解析にかかる時間を短縮できます。また、場合によっては実行時間も短縮できます。webpack や Rollup などのモジュールバンドラーを使う最新の JavaScript アプリの多くでは、バンドラーが不要なコードを自動的に取り除くことが期待されます。
アプリケーションとその依存関係を抽象構文木として考えてみましょう(構文木を「振る」ことで最適化します)。ツリー内の各ノードは、アプリに機能を提供する依存関係です。ツリーシェイキングでは、入力ファイルはグラフとして扱われます。グラフ内の各ノードは、コード内で「パート」と呼ばれるトップレベルの文です。ツリーシェイキングは、エントリーポイントから開始し、たどったパスをバンドルに含めるものとしてマークするグラフの走査です。
各コンポーネントは、シンボルを宣言したり、シンボルを参照したり、ほかのファイルに依存したりできます。「パート」もそれぞれ、副作用があるかどうかをマークされます。たとえば、let firstName = 'Jane' という文は、firstName がどこからも必要とされていない場合に、取り除いても確認可能な違いが生じないため、副作用がありません。一方、let firstName = getName() という文には副作用があります。firstName がどこからも必要とされていなくても、getName() の呼び出しを取り除くとコードの意味が変わってしまうためです。
インポート
ES2015 のモジュール構文(import と export)で定義されたモジュールのみ、ツリーシェイキングできます。モジュールのインポート方法によって、そのモジュールをツリーシェイキングできるかどうかが決まります。
ツリーシェイキングは、エントリーポイントファイルの副作用があるすべてのパートをたどることから始まり、新しいセクションに到達するまでグラフの辺をたどっていきます。走査が完了すると、JavaScript バンドルには走査中に到達したパートのみが含まれます。それ以外の部分は除外されます。
たとえば、次の utilities.js ファイルがあるとします。
export function read(props) {
return props.book
}
export function nap(props) {
return props.winks
}
次に、以下の index.js ファイルがあるとします。
import { read } from 'utilities';
eventHandler = (e) => {
read({ book: e.target.value })
}
この例では、nap() は重要ではないため、バンドルには含まれません。
副作用
ES6 モジュールをインポートすると、そのモジュールはただちに実行されます。コード内でモジュールのエクスポートをどこからも参照していなくても、実行中にモジュール自体がグローバルスコープに影響を与えることがあります(ポリフィルやグローバルスタイルシートなど)。これを副作用と呼びます。モジュール自体のエクスポートを参照していなくても、モジュールが何らかの値をエクスポートしている場合は、インポート時の特別な挙動により、ツリーシェイキングできません。
Webpack のドキュメントでは、ツリーシェイキングについての明確な説明と、ツリーシェイキングを損なわない方法を確認できます。