Tree shaking

Tree shaking — это метод оптимизации, применяемый в сборщиках JavaScript, таких как Webpack, Rollup и Parcel, который позволяет удалять неиспользуемый код из финального бандла. Этот процесс снижает размер файлов, улучшает производительность загрузки и повышает эффективность выполнения кода в браузере. Основная идея заключается в статическом анализе зависимостей модулей и исключении экспортов, которые не используются в приложении.

Принципы работы Tree Shaking

  1. ES6-модули как основа Tree shaking работает только с синтаксисом ES6 import и export. Это связано с тем, что компилятор может точно определить, какие экспорты используются и какие нет. CommonJS (require/module.exports) не позволяет проводить такой анализ на этапе сборки, так как динамическое присвоение делает статический анализ невозможным.

  2. Статический анализ кода Сборщик сканирует все модули, строит граф зависимостей и отмечает используемые экспорты. Экспорт, который нигде не используется, помечается как “мертвый код” (dead code) и исключается из финального бандла.

  3. Минификация и удаление мертвого кода После анализа мертвый код может быть удален на этапе минификации. Популярные инструменты, такие как Terser, умеют распознавать неиспользуемые функции и переменные, полностью исключая их из финального файла.

Настройка Tree Shaking в сборщиках

  • Webpack Чтобы Webpack корректно применял tree shaking, необходимо:

    • Использовать mode: "production" — автоматически включает оптимизацию, включая минимизацию и удаление неиспользуемого кода.
    • Применять import/export ES6 модулей.
    • Проверять, что сторонние библиотеки поддерживают ES6-модули (библиотеки с CommonJS будут включены полностью).

    Пример настройки минимизации в Webpack:

    const TerserPlugin = require("terser-webpack-plugin");
    
    module.exports = {
      mode: "production",
      optimization: {
        minimize: true,
        minimizer: [new TerserPlugin({
          terserOptions: {
            compress: { unused: true },
            mangle: true,
          },
        })],
      },
    };
  • Rollup Rollup изначально ориентирован на tree shaking. Он выполняет удаление неиспользуемого кода на этапе сборки, что делает его особенно эффективным для библиотек и приложений с модульной структурой.

Практические рекомендации

  1. Избегать динамических импортов там, где нужен строгий анализ Динамические выражения типа import(variable) могут быть полезны для ленивой загрузки модулей, но они не участвуют в tree shaking, поскольку сборщик не знает заранее, какой модуль будет импортирован.

  2. Использовать named exports вместо default export function funcA() {} позволяет сборщику точнее определять использование кода. Default-экспорт часто приводит к включению всего модуля целиком.

  3. Проверка конечного бандла Lighthouse может анализировать производительность и размер финального бандла. Если tree shaking не сработал, отчёт покажет избыточные зависимости и мёртвый код.

  4. Библиотеки и модульная совместимость

    • При выборе сторонних библиотек отдавать предпочтение тем, что предоставляют ES-модули (module поле в package.json).
    • Библиотеки, экспортирующие всё через CommonJS, снижают эффективность tree shaking.

Lighthouse и измерение эффекта Tree Shaking

Lighthouse позволяет оценить, насколько эффективно применены методы оптимизации, включая tree shaking:

  • Размер бандла: чем меньше неиспользуемого кода, тем быстрее загрузка страницы.
  • Время до интерактивности: удаление мёртвого кода сокращает время исполнения.
  • Рекомендации по оптимизации: отчёт Lighthouse часто выделяет крупные зависимости, которые не используются полностью, давая подсказки для улучшения.

Ошибки и подводные камни

  • Неиспользуемый код внутри функций Tree shaking удаляет только неиспользуемые экспорты, но не может удалить мёртвый код внутри функций, если функция используется. Для этого нужно ручное рефакторингование или применение дополнительной минификации с dead code elimination.

  • Побочные эффекты (side effects) Если модуль имеет побочные эффекты при импорте, сборщик не будет удалять его полностью, чтобы не нарушить работу программы. Для Webpack это можно контролировать через поле sideEffects в package.json:

    {
      "sideEffects": false
    }
  • Динамическая генерация экспорта Код типа export const a = someCondition ? func1 : func2; может мешать статическому анализу и снижать эффективность tree shaking.


Эта методология позволяет создавать лёгкие и производительные приложения, сокращая объём загружаемых скриптов, ускоряя рендеринг страницы и упрощая поддержку кода. Tree shaking в связке с Lighthouse является ключевым инструментом для анализа и оптимизации фронтенд-проектов на JavaScript.