При сборке современных JavaScript-приложений часто возникает ситуация, когда несколько точек входа используют одни и те же библиотеки, модули или утилиты. Без специальной оптимизации такие зависимости дублируются в итоговых бандлах, увеличивая общий размер загрузки и ухудшая производительность. Parcel автоматически решает эту проблему через механизм выделения общих зависимостей в shared bundles.
Parcel анализирует граф зависимостей приложения и строит единое дерево импортов. В процессе обхода:
Ключевая идея: если модуль используется несколькими чанками, он может быть вынесен в отдельный общий бандл.
Parcel выполняет эту оптимизацию автоматически, без необходимости ручной настройки разделения кода.
Shared bundles формируются на этапе оптимизации графа чанков. Parcel группирует модули по следующим критериям:
После анализа создаются отдельные чанки, содержащие общие модули. Эти чанки подключаются ко всем точкам входа, которые от них зависят.
В типичной структуре сборки Parcel выделяются:
Shared bundles выступают промежуточным уровнем, уменьшающим дублирование и оптимизирующим кэширование.
Рассмотрим условное приложение с двумя точками входа:
app-a.js
app-b.js
Обе используют библиотеку:
lodash
и внутренний модуль:
utils/format.js
Parcel строит граф:
app-a → lodash → format
app-b → lodash → format
В результате формируется shared bundle:
shared-1.js:
lodash
format.js
И отдельные entry bundles:
app-a.js
app-b.js
Каждый entry bundle получает ссылку на shared chunk вместо дублирования кода.
Parcel использует runtime-слой, который отвечает за:
Runtime хранит карту загруженных модулей и обеспечивает единичную инициализацию каждого shared модуля.
Shared bundles значительно улучшают эффективность HTTP-кэширования:
Особенно эффективно это работает для:
Dynamic import влияет на структуру shared bundles следующим образом:
import('./module.js')
Parcel:
Если один и тот же async модуль используется в нескольких местах, его зависимости также могут быть агрегированы в shared слой.
Несмотря на автоматическую оптимизацию, возможны ситуации, когда shared bundles не формируются:
Если точки входа не имеют пересечений по зависимостям, shared chunks не создаются.
При сложных условиях:
if (condition) {
import('module-a')
} else {
import('module-b')
}
Parcel может разделить зависимости, не объединяя их в общий слой.
При наличии:
lodash@4
lodash@3
модули считаются различными, и shared bundle не формируется.
Эффективная структура shared зависимостей достигается при соблюдении нескольких принципов:
Использование единых точек импорта:
import { formatDate } from '@/utils/date'
вместо дублирования логики в разных модулях.
Стабильные версии зависимостей уменьшают вероятность расщепления графа.
Чем менее запутан граф зависимостей, тем эффективнее Parcel выделяет shared chunks.
В монорепозиториях shared bundles приобретают дополнительное значение:
Parcel анализирует зависимости на уровне всего проекта, включая workspace-пакеты, что позволяет формировать кросс-пакетные shared chunks.
Shared bundles уменьшают:
Однако увеличивается количество HTTP-запросов, что компенсируется HTTP/2 и HTTP/3 мультиплексированием.
Parcel комбинирует несколько стратегий:
Shared bundles являются центральным механизмом между static и dynamic стратегиями.
Изменение одного общего модуля приводит к пересборке только соответствующего shared chunk. Остальные части приложения остаются неизменными.
Это достигается через:
Каждая страница использует общий набор библиотек, который выносится в shared chunk.
Часто используемые зависимости попадают в shared слой при пересечении async маршрутов.
Компоненты дизайн-системы становятся единым shared пакетом между приложениями.
Несмотря на автоматизацию, существуют ограничения:
Shared bundles не всегда означают минимальный размер, иногда балансируется между количеством запросов и объёмом кода.