peerDependencies и external в Rollup образуют один из ключевых механизмов управления границами библиотеки, определяя, какие зависимости должны оставаться на стороне потребителя пакета, а не попадать в итоговый бандл. В контексте современной JavaScript-экосистемы это напрямую влияет на корректность версий, размер сборки и предотвращение конфликтов зависимостей.
Поле peerDependencies в package.json
описывает зависимости, которые:
Типичный пример:
{
"peerDependencies": {
"react": ">=17 <19"
}
}
Смысл здесь заключается не в том, чтобы включить React в пакет, а в том, чтобы потребовать его наличие в окружении приложения, использующего библиотеку.
Такой подход решает проблему дублирования рантайм-библиотек. Например, если каждая библиотека будет поставлять собственную копию React, это приведёт к:
Rollup оперирует другой, но концептуально связанной абстракцией —
external.
В конфигурации Rollup:
export default {
input: 'src/index.js',
output: {
file: 'dist/index.js',
format: 'esm'
},
external: ['react']
};
Поле external говорит сборщику:
import как есть в итоговом коде.То есть:
import React from 'react';
останется импортом в выходном файле, а не будет инлайнен в сборку.
Хотя peerDependencies и external относятся
к разным уровням системы (npm и bundler), их логика совпадает:
исключение зависимости из сборки с переносом ответственности на
потребителя.
| Механизм | Уровень | Что означает |
|---|---|---|
| peerDependencies | package.json / npm | «Эта зависимость должна быть установлена в проекте» |
| external | Rollup | «Не включать эту зависимость в бандл» |
Вместе они формируют согласованную контрактную модель библиотеки:
peerDependencies описывает требования к окружению,external реализует это требование на уровне
сборки.Наличие peerDependencies само по себе не влияет на
результат сборки. Rollup не читает это поле автоматически (без
плагинов).
Рассмотрим пример:
{
"peerDependencies": {
"lodash": "^4.17.0"
}
}
Если в Rollup не указать:
external: ['lodash']
то итоговая сборка может:
Это приводит к нарушению контракта: потребитель устанавливает lodash, но библиотека использует собственную копию.
Обратная ситуация также возможна. Если указать:
external: ['react']
но не объявить react в peerDependencies,
возникают проблемы:
Таким образом:
external влияет на сборку,peerDependencies влияет на установку и
совместимость.Они не взаимозаменяемы.
{
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
}
}
export default {
input: 'src/index.js',
external: ['react', 'react-dom']
};
Здесь важно, что React:
Например, плагин для Vue:
{
"peerDependencies": {
"vue": "^3.0.0"
}
}
export default {
external: ['vue']
};
Такая связка гарантирует, что:
В реальных сборках часто используется автоматическое преобразование
peerDependencies в external.
Пример подхода:
import pkg from './package.json' assert { type: 'json' };
export default {
input: 'src/index.js',
external: Object.keys(pkg.peerDependencies || {})
};
Здесь достигается синхронизация:
Это снижает риск рассинхронизации конфигурации.
Обычно включаются в бандл, если не указаны в
external.
{
"dependencies": {
"lodash": "^4.17.0"
}
}
Если Rollup не исключит lodash, он попадёт в итоговый файл.
Используются только в процессе сборки:
Они никогда не должны попадать в итоговый бандл.
Представляют особый контракт:
Связка peerDependencies + external решает одну из самых критичных проблем JavaScript-экосистемы — дублирование рантайм-библиотек.
Если библиотека A и библиотека B обе включают React:
peerDependencies,external,В монорепозиториях (pnpm, yarn workspaces) связь становится ещё более важной.
Даже если зависимость физически присутствует в
node_modules, peerDependencies всё равно:
Rollup в таких проектах:
external,Симптомы:
Причина:
Симптомы:
Причина:
"peerDependencies": {
"react": "^18"
}
но в проекте используется React 17.
Симптомы:
Rollup в этой ситуации корректен, но контракт нарушен.
Связка peerDependencies + external формирует фундаментальную архитектурную границу библиотеки:
Эта модель позволяет библиотекам: