Вынесение зависимостей в external — один из ключевых механизмов Rollup, который определяет, какие модули попадут в итоговый бандл, а какие останутся внешними и будут загружаться отдельно в рантайме. Эта концепция напрямую влияет на размер сборки, стратегию публикации библиотек и способ интеграции с окружением (Node.js, браузер, CDN).
В основе механизма лежит параметр external в
конфигурации Rollup. Он позволяет явно указать, какие зависимости не
должны быть включены в итоговый файл. Rollup при этом полностью
исключает их из графа сборки, заменяя импорт на обращение к внешнему
ресурсу.
Самая простая форма — массив строк, где перечисляются имена пакетов:
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'esm'
},
external: ['lodash', 'axios']
};
В этом случае любые импорты:
import _ from 'lodash';
import axios from 'axios';
не будут включены в бандл. Вместо этого Rollup оставит их как есть.
Результат работы external зависит от формата выходного
файла.
При format: 'esm' внешние зависимости сохраняются как
стандартные import:
import _ from 'lodash';
Браузер или Node.js обязан самостоятельно разрешить этот импорт.
При format: 'cjs' зависимости преобразуются в
require:
const _ = require('lodash');
Rollup не пытается резолвить модуль, оставляя ответственность системе выполнения.
Для UMD и IIFE ситуация отличается: внешние зависимости должны быть представлены через глобальные переменные:
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.umd.js',
format: 'umd',
name: 'MyLib',
globals: {
lodash: '_'
}
},
external: ['lodash']
};
В этом случае Rollup заменяет импорт на обращение к глобальной
переменной _.
Помимо массива можно использовать функцию, что позволяет реализовать более гибкую логику:
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'esm'
},
external: (id) => {
return id.startsWith('lodash');
}
};
Функция получает идентификатор модуля и возвращает true,
если модуль должен считаться внешним.
Часто используется для:
node_modulesРаспространённый паттерн для библиотек:
export default {
external: id => !id.startsWith('.') && !id.startsWith('/')
};
Здесь все пакеты из node_modules считаются внешними, а
локальные файлы остаются внутри бандла.
Такой подход часто используется при разработке библиотек, которые публикуются в npm и не должны дублировать зависимости конечному приложению.
Часто external синхронизируют с peerDependencies из
package.json:
import pkg from './package.json' assert { type: 'json' };
export default {
external: Object.keys(pkg.peerDependencies || {})
};
Это гарантирует, что зависимости, ожидаемые от хоста, не попадут в бандл.
В реальных проектах external часто строится на метаданных пакета.
dependencies обычно не выносятся наружу в
приложенияхpeerDependencies почти всегда выносятся в external при
сборке библиотекТипичный сценарий:
import pkg from './package.json' assert { type: 'json' };
const external = [
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.peerDependencies || {})
];
export default {
input: 'src/index.js',
output: {
file: 'dist/index.js',
format: 'esm'
},
external
};
external работает не только с именами пакетов, но и с путями модулей.
external: [
'react',
'react-dom',
'/virtual-module'
]
Также можно учитывать alias-конфигурации, если используется плагин
@rollup/plugin-alias, поскольку Rollup принимает решение об
external до финального резолва модулей.
external полностью исключает модуль из графа зависимостей Rollup. Это означает:
Таким образом external — это “жёсткое исключение”, в отличие от оптимизаций внутри включённых модулей.
При использовании import() поведение остаётся
аналогичным:
import('lodash').then(_ => {
console.log(_.chunk([1,2,3], 2));
});
Если lodash объявлен как external, Rollup оставит
динамический импорт без изменений.
Однако важно учитывать, что в некоторых форматах (например, IIFE) динамические внешние импорты могут быть невалидны без дополнительной инфраструктуры загрузчика.
external: ['src/utils']
В этом случае модуль может быть исключён из сборки, хотя должен быть встроен.
При UMD-сборке:
external: ['lodash'],
output: {
format: 'umd',
globals: {
lodash: 'lodash'
}
}
Если глобальная переменная не соответствует реальному окружению, код упадёт в рантайме.
Некоторые пытаются выносить подмодули:
external: ['lodash/map']
Это часто приводит к неконсистентному поведению, так как резолв пакета может отличаться в зависимости от плагинов.
Использование external напрямую определяет:
Для библиотек external становится инструментом разделения ответственности между автором пакета и потребителем.
При использовании:
output: {
preserveModules: true
}
external продолжает работать на уровне модулей, исключая их из структуры вывода, но сохраняя файловую структуру для остальных частей проекта.
При сборке для CDN часто внешние зависимости заменяются на глобальные
переменные, а сами библиотеки подключаются через
<script>:
<script src="https://cdn.jsdelivr.net/npm/lodash"></script>
<script src="bundle.js"></script>
Rollup в этом случае должен быть настроен так:
export default {
external: ['lodash'],
output: {
format: 'iife',
globals: {
lodash: '_'
}
}
};
В сложных проектах external может формироваться динамически:
import pkg from './package.json' assert { type: 'json' };
const baseExternal = [
...Object.keys(pkg.peerDependencies || {})
];
const nodeExternal = id =>
baseExternal.includes(id) || id.startsWith('node:');
export default {
external: nodeExternal
};
Такой подход позволяет учитывать разные источники зависимостей и расширять конфигурацию без ручного редактирования списка.
external применяется до большинства трансформаций, но после базового анализа входных модулей. Это означает, что плагины резолва (например, alias или node-resolve) могут повлиять на идентификаторы, которые попадут в external-функцию.
Поэтому логика external должна учитывать реальные id модулей, а не исходные пути импорта в коде.
external определяет границу между:
Эта граница особенно важна при разработке:
Правильная настройка external позволяет избежать дублирования зависимостей, конфликтов версий и увеличения размера бандла, сохраняя при этом предсказуемость поведения в рантайме.