Tree shaking

Vivus часто используется в связке с современными сборщиками модулей, где ключевую роль играет tree shaking — механизм удаления неиспользуемого кода на этапе сборки. Для библиотек анимации SVG это особенно критично, поскольку даже небольшое увеличение бандла заметно влияет на скорость загрузки и время до интерактивности.

Tree shaking опирается на статический анализ ESM-модулей. Сборщик (Webpack, Rollup, Vite) строит граф зависимостей и исключает экспортированные сущности, которые не используются в конечной программе.

Основные условия эффективного tree shaking:

  • использование ES Modules (import / export)
  • отсутствие динамических require
  • отсутствие побочных эффектов в модулях
  • корректная настройка sideEffects в package.json

При нарушении хотя бы одного условия код начинает восприниматься как «небезопасный для удаления».

Архитектура Vivus и влияние на дерево зависимостей

Библиотека Vivus изначально разрабатывалась как класс для поэтапного рисования SVG. В типичной поставке встречаются несколько вариантов сборки:

  • UMD-версия (для прямого подключения через <script>)
  • ESM-версия (для современных бандлеров)
  • иногда отдельные минифицированные сборки

UMD-версия не подлежит tree shaking в принципе, поскольку весь код представляет собой единый модуль без экспортируемых частей. ESM-версия, напротив, позволяет удалять неиспользуемые элементы при корректной настройке сборщика.

Причины, по которым tree shaking может не работать

Даже при использовании ESM-сборки Vivus tree shaking часто не срабатывает из-за следующих факторов:

1. Побочные эффекты внутри модуля

Если модуль выполняет код при импорте (например, регистрирует глобальные объекты или сразу инициализирует логику), сборщик помечает его как имеющий side effects.

Пример типичной проблемы:

  • инициализация внутренних утилит при загрузке модуля
  • регистрация глобальных polyfill
  • привязка к window или document на уровне импорта

2. Отсутствие корректного sideEffects флага

В package.json библиотеки может отсутствовать:

{
  "sideEffects": false
}

Без этого флага bundler часто перестаёт агрессивно удалять неиспользуемые части.

3. Импорт всего пакета

Наиболее частая ошибка:

import Vivus from 'vivus';

Такой импорт заставляет сборщик включить весь код библиотеки, даже если используется только минимальный функционал.

Оптимальные модели импорта

Tree shaking становится эффективным только при точечном импорте ESM-сборки.

Прямой импорт ESM-версии

import Vivus from 'vivus/dist/vivus.es.js';

В этом случае сборщик может анализировать модульную структуру и удалять неиспользуемые части.

Ленивый импорт через dynamic import

const Vivus = await import('vivus');

или:

const { default: Vivus } = await import('vivus');

Такой подход полезен при анимациях, запускаемых только при появлении элемента в viewport.

Tree shaking и SVG-анимации

SVG-анимации имеют особенность: большая часть кода часто сосредоточена вокруг:

  • расчёта длины пути (getTotalLength)
  • интерполяции stroke-dasharray
  • RAF-циклов (requestAnimationFrame)
  • парсинга DOM SVG

Tree shaking в таких библиотеках не столько уменьшает объём логики анимации, сколько позволяет убрать вспомогательные модули:

  • утилиты математических операций
  • альтернативные режимы анимации
  • вспомогательные polyfill-слои

Влияние структуры экспорта Vivus

Если библиотека экспортирует единственный класс:

export default class Vivus { ... }

то tree shaking практически бесполезен: весь класс считается обязательным.

Если же присутствуют дополнительные экспортируемые модули:

export { Vivus }
export { EasingFunctions }
export { Utils }

то становится возможным удаление вспомогательных частей при их неиспользовании.

Webpack и tree shaking для Vivus

В Webpack 4+ tree shaking включён по умолчанию в production mode, но требует корректной конфигурации:

module.exports = {
  mode: 'production',
  optimization: {
    usedExports: true
  }
};

Критически важен флаг mode: production, поскольку именно он активирует TerserPlugin, удаляющий мёртвый код.

Если импортируется Vivus как CommonJS:

const Vivus = require('vivus');

tree shaking отключается полностью.

Rollup и максимальная эффективность удаления кода

Rollup считается наиболее «чистым» инструментом для tree shaking. При подключении ESM-версии Vivus:

  • строится точный граф зависимостей
  • удаляются неиспользуемые экспорты
  • минимизируются вспомогательные функции

Особенно эффективно при сборке библиотек поверх Vivus, где используется только один режим анимации.

Vite и поведение на уровне dev/prod

Vite использует Rollup на этапе production build, поэтому:

  • в dev режиме tree shaking не применяется в полном объёме
  • в production происходит агрессивная оптимизация

При этом Vivus, как правило, попадает в pre-bundled зависимости через esbuild, что может «заморозить» структуру модуля до этапа tree shaking Rollup.

Побочные эффекты SVG и влияние на удаление кода

SVG-анимация часто связана с DOM:

  • доступ к document.querySelector
  • изменение атрибутов SVG-элементов
  • вычисления геометрии

Такие операции считаются side effects, и даже если часть логики теоретически не используется, сборщик может сохранить весь модуль из-за потенциального влияния на DOM.

Практика уменьшения бандла Vivus через архитектуру

Эффективная стратегия tree shaking часто заменяется архитектурным разделением:

  • разделение анимаций по модулям
  • динамическая загрузка компонентов
  • изоляция инициализации Vivus в отдельных чанках
  • отказ от глобальных инициализаций

Пример логического разделения:

  • модуль только для инициализации SVG
  • модуль только для параметров анимации
  • модуль триггеров (scroll, click, intersection observer)

Типичные ошибки, блокирующие tree shaking

  • импорт всей библиотеки ради одного эффекта
  • использование CommonJS-сборок
  • смешивание ESM и CJS модулей
  • отсутствие production build
  • использование глобального namespace вместо модульной структуры
  • ранняя инициализация Vivus при загрузке страницы

Связь tree shaking и производительности SVG-анимаций

Хотя tree shaking напрямую не ускоряет выполнение анимации, он влияет на:

  • время загрузки JavaScript
  • скорость парсинга скриптов
  • объем main thread работы до первого рендера
  • вероятность блокировки интерфейса при старте страницы

Для SVG-анимаций, запускающихся при скролле, это особенно заметно: уменьшение начального JS-бандла снижает задержку перед первой активацией анимации.