Принцип работы: статический анализ графа модулей

Статический анализ графа модулей является центральным механизмом работы Rollup и определяет его фундаментальное отличие от других сборщиков модулей. В основе подхода лежит построение полного представления зависимостей проекта на этапе сборки без выполнения кода. Это позволяет точно определить, какие части приложения действительно используются, а какие могут быть безопасно исключены.

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

Каждый модуль рассматривается как узел графа, а импорт — как направленное ребро. В результате формируется ориентированный ациклический граф (DAG), где:

  • узлы — ES-модули;
  • рёбра — связи import / export;
  • корень — entry point.

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

Парсинг и построение AST

Каждый модуль проходит этап парсинга, в ходе которого код преобразуется в абстрактное синтаксическое дерево (AST). Rollup использует AST для точного извлечения:

  • деклараций import и export;
  • именованных и дефолтных экспортов;
  • динамических конструкций, если они поддерживаются плагинами;
  • ссылок на идентификаторы внутри модуля.

AST служит основой для дальнейшего анализа связей между модулями и позволяет выполнять точечные трансформации без потери контекста.

Разрешение зависимостей

После извлечения импортов Rollup выполняет процесс разрешения модулей. Он включает определение реального пути к каждому импортируемому ресурсу с учётом:

  • относительных и абсолютных путей;
  • алиасов, заданных через плагины;
  • расширений файлов;
  • условных экспортов в package.json (поле exports);
  • встроенных механизмов Node.js-резолвинга при необходимости.

Результатом является построение полного списка модулей, участвующих в графе.

Связывание модулей в единый граф

Когда все зависимости разрешены, Rollup формирует связанный граф, где каждый модуль содержит:

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

Особенность Rollup заключается в том, что граф строится с учётом конкретных используемых символов, а не только модулей целиком. Это обеспечивает более глубокий уровень анализа по сравнению с системами, которые оперируют только файловыми зависимостями.

Анализ используемости кода

Ключевой этап статического анализа — определение того, какие части кода действительно используются. Rollup выполняет анализ достижимости (reachability analysis), начиная с точки входа.

Процесс включает:

  • пометку экспортов, которые используются в entry point;
  • рекурсивное распространение меток использования по графу;
  • исключение неиспользуемых экспортов и даже целых модулей;
  • отслеживание цепочек реэкспортов через export { ... } from.

Если символ не достигается из точки входа ни по одной цепочке зависимостей, он считается мёртвым кодом.

Tree-shaking как результат графового анализа

На основе построенного графа и анализа достижимости Rollup выполняет tree-shaking. В отличие от поверхностной фильтрации файлов, здесь учитывается:

  • использование конкретных функций и переменных;
  • побочные эффекты модулей;
  • чистота выражений (определяется через аннотации и анализ кода);
  • статичность импортов и экспортов.

Если модуль содержит побочные эффекты, он может быть частично или полностью сохранён, даже если его экспорты не используются.

Обработка циклических зависимостей

Хотя граф модулей стремится к ацикличности, в реальных проектах возможны циклические зависимости. Rollup обрабатывает их путём:

  • построения предварительного графа;
  • выявления циклов во время обхода;
  • корректного разрешения порядка инициализации;
  • сохранения семантики ES-модулей, где циклы допустимы на уровне спецификации.

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

Инлайн-реэкспорты и трансформации графа

Rollup учитывает конструкции вида:

  • export * from
  • export { a, b } from
  • комбинированные реэкспорты через промежуточные модули

Такие случаи приводят к необходимости трансформации графа, при которой:

  • создаются виртуальные связи между экспортами;
  • происходит “протягивание” символов через промежуточные узлы;
  • оптимизируется количество переходов между модулями.

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

Влияние плагинов на граф

Плагинная система Rollup может модифицировать граф на разных этапах:

  • добавлять виртуальные модули;
  • изменять пути резолвинга;
  • трансформировать AST до анализа зависимостей;
  • вмешиваться в процесс tree-shaking через метаданные.

Это делает граф не только результатом синтаксического анализа, но и результатом последовательной цепочки трансформаций.

Оптимизация графа перед генерацией бандла

После завершения анализа Rollup выполняет финальную оптимизацию графа:

  • удаление неиспользуемых узлов;
  • объединение связанных модулей при необходимости;
  • упрощение цепочек реэкспортов;
  • минимизация количества промежуточных связей.

Эти шаги подготавливают структуру к финальной стадии — генерации выходного кода.

Связь графа модулей с итоговым бандлом

Граф модулей напрямую определяет структуру итогового бандла. Порядок включения кода, область видимости переменных и структура обёрток формируются на основе топологии графа.

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