Skip to content
⚠️ This article was written in 2018. Some content may be outdated.

フロントエンドパフォーマンス最適化:Tree Shakingの深掘り実践

Tree Shakingはモダンなフロントエンドエンジニアリングの重要な最適化手段ですが、実際の効果が期待通りにならないことがよくあります。背後にある理由を深く理解する価値があります。

Tree Shakingとは

Tree ShakingはES Moduleの静的な特性を活用し、バンドル時に使用されていないコード(デッドコードの削除)を取り除きます:

javascript
// utils.js
export function add(a, b) {
  return a + b;
}
export function subtract(a, b) {
  return a - b;
} // 使用されていない

// main.js
import { add } from "./utils";
console.log(add(1, 2));
// subtractはインポートされていない — Tree Shakingでバンドルから除外される

前提条件:ES Module(import/export)を使用する必要があります。CommonJS(require)はTree Shakingできません。

Tree Shakingが効かない場合の理由

理由1:CommonJSモジュールを使用している

javascript
// ❌ CommonJS — Tree Shaking不可
const { add } = require("./utils");

// ✅ ES Module
import { add } from "./utils";

Babel 7以前は@babel/preset-envがデフォルトでES ModuleをCommonJSに変換していたため、Tree Shakingが無効化されていました。

修正:

javascript
// babel.config.js
module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        modules: false, // ES Moduleを変換しない — webpackに任せる
      },
    ],
  ],
};

理由2:副作用(Side Effects)

モジュールに副作用がある場合(実行時にグローバル状態を変更する)、Tree Shakingは保守的にそれを保持します:

javascript
// 副作用のあるモジュール:実行時にグローバルを変更
window.myLib = { version: '1.0' }
export function doSomething() { ... }

package.jsonでどのファイルに副作用があるかを宣言:

json
{
  "sideEffects": [
    "*.css", // CSSファイルは副作用あり(グローバルスタイル)
    "src/polyfills.js"
  ]
}

または、完全に副作用がないことを宣言:

json
{
  "sideEffects": false
}

理由3:インポート方法が間違っている

javascript
// ❌ パッケージ全体をインポート
import _ from "lodash";
_.chunk([1, 2, 3, 4], 2); // lodash全体がバンドルされる

// ✅ 特定の関数をインポート
import chunk from "lodash/chunk";

// ✅ lodash-es(ES Module版)を使用
import { chunk } from "lodash-es";

理由4:名前空間インポート + 分割代入

javascript
// ❌ オンデマンドインポートに見えるが、実際はモジュール全体をインポート
import * as utils from "./utils";
const { add } = utils;

// ✅ 直接の名前付きインポート
import { add } from "./utils";

Tree Shakingの効果を検証する

javascript
// ビルド後にバンドル内に削除した関数名が含まれているか確認
// Tree Shakingが機能していれば、削除した関数名は現れないはず
grep -r "subtract" dist/

またはwebpack-bundle-analyzerを使って視覚的に確認できます。

サードパーティライブラリのTree Shaking

ES Moduleを提供しているライブラリのみTree Shakingをサポートします:

ライブラリTree Shakingサポート
lodash❌ CommonJS
lodash-es✅ ES Module
vue✅(2.6+)
element-uibabel-plugin-componentが必要
date-fns✅ ES Module
moment❌ day.jsへの移行を推奨

Element UIのTree Shaking

javascript
// 方法1:babel-plugin-component(自動オンデマンドインポート)
// babel.config.js
{
  plugins: [
    [
      "component",
      { libraryName: "element-ui", styleLibraryName: "theme-chalk" },
    ],
  ];
}

// 方法2:手動オンデマンドインポート
import { Button, Input } from "element-ui";

まとめ

  • Tree ShakingにはES Moduleが必要 — CommonJSは使わない
  • BabelでES Moduleの変換を防ぐためにmodules: falseを設定
  • package.jsonsideEffectsを宣言してバンドラーのより賢い判断を助ける
  • lodashなどの大きなライブラリはES Module版(lodash-es)を使うか個別関数をインポート

MIT Licensed