В JavaScript-проектах существует несколько уровней зависимости:
зависимости приложения, транзитивные зависимости и зависимости, которые
библиотека ожидает получить от окружения потребителя. В контексте
сборщика Parcel ключевое значение приобретают два механизма —
peerDependencies и externals, которые
определяют границы включения кода в итоговую сборку.
Parcel, как сборщик, ориентирован на автоматическое разрешение модулей, но при создании библиотек и переиспользуемых пакетов требуется явное управление тем, что должно попасть в бандл, а что должно остаться внешним.
peerDependencies в package.json задаёт
зависимость не на установку, а на совместимость.
peerDependencies описывает:
Иначе говоря, это контракт на окружение, а не на поставку кода.
Пример:
{
"name": "my-ui-lib",
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
}
}
Это означает:
reactreact уже существует в
приложенииНаиболее частый сценарий — библиотеки, работающие поверх React или Vue.
Если библиотека случайно включает собственную копию React:
peerDependencies предотвращают эту проблему на уровне
менеджера пакетов.
Parcel не интерпретирует peerDependencies как инструкцию
для бандлинга напрямую. Он опирается на следующие принципы:
node_modulesВажно различать:
peerDependencies — декларация npm-уровняParcel не исключает автоматически peerDependencies из
бандла, если они импортируются.
import React from "react";
Если react указан только в
peerDependencies, Parcel всё равно:
Это создаёт риск дублирования при библиотечной сборке.
externals в Parcel — механизм явного исключения
зависимостей из итогового bundle.
Он используется, когда модуль должен оставаться внешним и предоставляться средой выполнения.
Если модуль объявлен как external:
В Parcel v2 externals задаются через package.json в
секции targets:
{
"name": "my-ui-lib",
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
},
"targets": {
"default": {
"external": ["react", "react-dom"]
}
}
}
После настройки:
import React from "react";
Parcel:
Несмотря на схожую цель, механизмы решают разные задачи.
node_modules| Механизм | Уровень | Назначение |
|---|---|---|
| peerDependencies | npm install | предотвращение дублирования пакетов |
| externals | bundling | исключение кода из сборки |
Корректная библиотечная конфигурация обычно требует комбинации:
{
"peerDependencies": {
"react": ">=18"
},
"targets": {
"default": {
"external": ["react"]
}
}
}
Такой подход обеспечивает:
{
"name": "ui-kit",
"version": "1.0.0",
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
},
"dependencies": {
"clsx": "^2.0.0"
},
"targets": {
"default": {
"external": ["react", "react-dom"]
}
}
}
clsx попадает в bundle (обычная зависимость)react и react-dom остаются внешнимиParcel не различает семантику peerDependencies при
обходе графа зависимостей:
Это часто приводит к ошибке:
“peer dependency установлен, но всё равно попал в bundle”
Решение — явное использование external.
Без externals возможны следующие проблемы:
Причина:
В monorepo структурах (например, pnpm workspace):
В таких условиях externals становится обязательным
инструментом стабилизации сборки.
Важно учитывать:
Это отличается от обычных зависимостей, где Parcel удаляет неиспользуемые экспорты.
Типичные признаки проблем:
Диагностика включает:
Корректная архитектура библиотечного пакета в Parcel строится по следующей логике: