Выборочная сборка изменённых таргетов

В Parcel концепция таргетов (targets) определяет, в какие конечные окружения и форматы будет собран проект. Один и тот же исходный код может одновременно транслироваться в несколько независимых выходов: браузерный бандл, Node.js-модуль, ESM-библиотеку или специализированный сборочный формат для встраивания.

Каждый таргет описывает собственный набор параметров: директорию вывода, окружение выполнения, формат модулей, требования к совместимости и дополнительные опции трансформации. При этом Parcel рассматривает таргеты не как простые конфигурации, а как изолированные графы сборки, построенные поверх общего графа исходников.

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


Разделение графа зависимостей по таргетам

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

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

Ключевая особенность заключается в том, что Parcel не пересобирает граф целиком при каждом изменении. Вместо этого поддерживается связь:

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

Это позволяет отслеживать влияние изменения не глобально, а локально — только в тех таргетах, где модуль реально используется.


Механизм определения изменённых узлов

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

Если модуль используется в нескольких таргетах, пересчёт выполняется выборочно:

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

Такой подход уменьшает объём работы при инкрементальной сборке и особенно эффективен в проектах с несколькими выходами (например, библиотека + приложение).


Инкрементальная пересборка и кэширование

Parcel опирается на многоуровневое кэширование, где результат каждого этапа трансформации фиксируется с учётом входных параметров:

  • содержимое файла
  • конфигурация трансформеров
  • контекст таргета
  • зависимости модуля

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

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


Изоляция таргетов и различия окружений

Разные таргеты могут требовать различных преобразований одного и того же исходного кода. Например:

  • браузерный таргет ориентирован на совместимость с ECMAScript и полифиллы
  • Node.js-таргет исключает браузерные трансформации
  • ESM-таргет сохраняет модульную структуру без агрегации

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

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


Алгоритм выборочной пересборки

Процесс пересборки при изменении файла можно описать последовательностью:

  1. фиксация изменения исходного ресурса
  2. вычисление нового хеша содержимого
  3. проверка кэша трансформаций
  4. инвалидирование узлов графа зависимостей
  5. ограничение области распространения инвалидности таргетом
  6. повторная генерация только затронутых узлов
  7. обновление выходных бандлов для соответствующих таргетов

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


Поведение в режиме наблюдения

В watch-режиме Parcel удерживает граф сборки в памяти и отслеживает изменения файловой системы.

Каждое изменение приводит к локальному пересчёту:

  • обновляются только затронутые модули
  • пересобираются только связанные таргеты
  • неизменённые ветки графа сохраняются в кэше

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

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


Сценарии многотаргетной сборки

В проектах библиотечного типа часто используются одновременно несколько таргетов:

  • main для CommonJS
  • module для ESM
  • browser для клиентского окружения

При изменении внутреннего модуля библиотеки пересобираются только те таргеты, где модуль включён в итоговую цепочку импортов. Например, Node-таргет может остаться неизменным, если изменение затрагивает только браузерную специфичную часть.

В монорепозиториях эффект усиливается: общие зависимости переиспользуются между пакетами, но пересборка ограничивается только теми пакетами, где произошли изменения, а внутри них — только активными таргетами.


Оптимизация через разделение бандлов

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

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

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


Распространение изменений в зависимостях

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

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


Кэш-ориентированная селективность

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

  • исходный код
  • конфигурация трансформации
  • окружение таргета
  • параметры оптимизации

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


Поведение при пересечении таргетов

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

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


Практическая значимость селективной пересборки

Механизм выборочной сборки изменённых таргетов особенно критичен для:

  • библиотек с несколькими форматами экспорта
  • приложений с разделением клиент/сервер
  • монорепозиториев с общими зависимостями
  • проектов с активной разработкой и частыми изменениями

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