Инвалидация кэша

Архитектура кэша и его роль в сборке

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

Parcel сохраняет промежуточные результаты:

  • трансформации исходного кода (Babel, TypeScript, PostCSS и др.)
  • разрешение зависимостей
  • результаты минификации
  • сведения о хэшах ассетов
  • структуру графа модулей

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


Контент-хэш как основа инвалидации

Основной механизм инвалидации кэша в Parcel основан на content hashing — вычислении хэша от содержимого файла и его зависимостей.

Хэш формируется из нескольких факторов:

  • исходного кода модуля
  • зависимых импортов
  • применённых трансформаций (Babel, TypeScript и т.д.)
  • конфигурации проекта
  • версии плагинов и резолверов

Любое изменение одного из этих элементов приводит к изменению хэша, что автоматически делает кэш устаревшим.

Таким образом реализуется принцип:

изменение входных данных → изменение хэша → новая версия артефакта


Граф зависимостей и каскадная инвалидация

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

Инвалидация происходит не только на уровне одного файла, но и каскадно:

  • изменение модуля A
  • приводит к изменению его хэша
  • пересчитываются зависимости B, C, D
  • обновляется итоговый бандл

При этом Parcel избегает полного пересборки проекта за счёт изолированного пересчёта подграфов.

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


Диск-кэш (.parcel-cache)

Parcel использует директорию .parcel-cache для хранения промежуточных данных.

Внутри кэша сохраняются:

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

Кэш организован как контент-адресуемое хранилище. Это означает, что ключом является хэш содержимого, а не путь к файлу.

Такой подход обеспечивает:

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

Инвалидация при изменении исходного кода

При изменении файла Parcel выполняет цепочку проверок:

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

Если изменения отсутствуют, модуль берётся из кэша без повторной обработки.

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


Инвалидация при изменении конфигурации

Изменения конфигурационных файлов приводят к более широкой инвалидации.

К таким файлам относятся:

  • package.json
  • .babelrc
  • tsconfig.json
  • конфигурация Parcel
  • плагины и их версии

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


Инвалидация при изменении зависимостей

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

Parcel отслеживает:

  • версии пакетов
  • содержимое установленных модулей
  • lock-файлы (package-lock.json, yarn.lock, pnpm-lock.yaml)

Любое изменение этих данных приводит к пересчёту соответствующих кэш-ключей.


HMR и частичная инвалидация в dev-режиме

В режиме разработки используется Hot Module Replacement (HMR), который тесно связан с системой инвалидации кэша.

При изменении файла:

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

Parcel стремится минимизировать перезагрузку страницы, заменяя только изменённые участки кода.

Инвалидация здесь работает на уровне модулей, а не всего бандла.


Инвалидация при изменении плагинов и трансформеров

Parcel использует систему плагинов и трансформеров, которые могут влиять на результат сборки.

Если изменяется:

  • версия плагина
  • логика трансформации
  • порядок применения плагинов

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

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


Стратегии ускорения повторных сборок

Parcel использует несколько стратегий оптимизации кэша:

1. Контент-адресуемый кэш Одинаковые входные данные всегда дают одинаковый результат.

2. Инкрементальная сборка Обновляются только затронутые узлы графа.

3. Параллельное выполнение трансформаций Независимые модули обрабатываются одновременно.

4. Ленивое вычисление Некоторые оптимизации выполняются только при необходимости.


Очистка и сброс кэша

В некоторых ситуациях кэш может стать неконсистентным, например:

  • изменение версий Parcel
  • обновление плагинов
  • повреждение .parcel-cache

В таких случаях применяется полная инвалидация:

  • удаление .parcel-cache
  • принудительная пересборка всех модулей
  • регенерация графа зависимостей

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


Проблемы и тонкости инвалидации

Механизм кэширования и инвалидации может сталкиваться с рядом сложностей:

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

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

3. Побочные эффекты трансформаций Если трансформер зависит от состояния окружения, кэширование теряет детерминизм.

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


Контроль детерминизма сборки

Для корректной работы системы кэширования важен детерминизм всех этапов сборки:

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

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