Поле globals и внешние зависимости

При сборке модулей Rollup по умолчанию стремится включить все импортируемые зависимости в итоговый бандл. Такое поведение эффективно для библиотек и приложений, где требуется максимальная автономность результата. Однако в реальных проектах часть зависимостей часто предполагается внешней: они уже доступны в окружении выполнения (браузер через CDN, Node.js, другой бандл, система плагинов).

Именно для этого используется механизм внешних зависимостей через поле external в конфигурации Rollup.

Поле external

external определяет модули, которые не должны попадать в итоговый бандл. Вместо их включения Rollup оставляет import/require как есть либо трансформирует их в обращения к глобальным переменным — в зависимости от формата вывода.

Простейшая форма:

export default {
  input: 'src/index.js',
  output: {
    file: 'dist/bundle.js',
    format: 'esm'
  },
  external: ['lodash', 'react']
}

В этом случае:

  • lodash и react не будут включены в сборку
  • импорт останется внешним
  • ответственность за их наличие переносится на окружение
import _ from 'lodash';
import React from 'react';

Rollup оставит эти импорты без инлайнинга.

Функциональная форма external

Часто требуется более гибкая логика:

external: (id) => id.startsWith('react') || id === 'lodash'

Это позволяет:

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

Как Rollup обрабатывает внешние зависимости

Поведение зависит от формата сборки:

  • esm — внешние зависимости остаются как import
  • cjs — превращаются в require
  • umd / iife — заменяются на обращения к глобальным переменным через output.globals

Именно последний случай делает поле globals критически важным.


Поле globals

globals используется только вместе с форматами umd и iife. Оно задаёт соответствие между именем модуля и глобальной переменной, доступной в среде выполнения.

Пример:

export default {
  input: 'src/index.js',
  external: ['react'],
  output: {
    file: 'dist/bundle.umd.js',
    format: 'umd',
    name: 'MyLibrary',
    globals: {
      react: 'React'
    }
  }
}

Механика работы

При такой конфигурации:

import React from 'react';

превращается в:

var React = window.React;

или аналогичную форму в зависимости от окружения.


Связь external и globals

Эти два поля всегда работают вместе в UMD/IIFE сборках:

  • external говорит: «не включать модуль в бандл»
  • globals говорит: «как этот модуль называется в глобальной области»

Без globals Rollup не сможет корректно заменить внешние зависимости в UMD/IIFE формате, что приведёт к ошибкам выполнения.


Пример комплексной конфигурации

export default {
  input: 'src/index.js',
  external: ['react', 'react-dom', 'lodash'],
  output: [
    {
      file: 'dist/library.cjs.js',
      format: 'cjs'
    },
    {
      file: 'dist/library.esm.js',
      format: 'esm'
    },
    {
      file: 'dist/library.umd.js',
      format: 'umd',
      name: 'Library',
      globals: {
        react: 'React',
        'react-dom': 'ReactDOM',
        lodash: '_'
      }
    }
  ]
}

Здесь один и тот же исходный код компилируется в три формата:

  • CommonJS для Node.js
  • ESM для современных сборщиков
  • UMD для браузерного использования через <script>

Практическое использование в браузере

Подключение через CDN

При использовании UMD-бандла зависимость должна быть загружена отдельно:

<script src="https://unpkg.com/react/umd/react.production.min.js"></script>
<script src="dist/library.umd.js"></script>

В этом случае React уже существует как глобальная переменная, и Rollup использует её благодаря globals.


Типичные сценарии применения

Библиотеки поверх React

При разработке UI-библиотеки почти всегда:

  • react и react-dom объявляются внешними
  • они не включаются в бандл
  • используются через globals

Причина — избежать дублирования React в приложении-потребителе.


Плагины и расширения

Для библиотек-плагинов (например, для редакторов или графических движков):

  • ядро системы часто external
  • доступ осуществляется через глобальный объект

Работа с lodash и утилитами

external: ['lodash'],
output: {
  globals: {
    lodash: '_'
  }
}

Это позволяет использовать CDN-версию lodash без включения в бандл.


Автоматизация через regex в external

Частый паттерн — исключение всех зависимостей из node_modules:

external: (id) => !id.startsWith('.') && !id.startsWith('/')

Логика:

  • относительные пути (./, ../) остаются внутри бандла
  • пакеты из node_modules становятся внешними

Такой подход характерен для библиотек, но опасен для приложений, так как требует контроля зависимостей на стороне окружения.


Влияние на tree-shaking

Важно различать:

  • external полностью исключает модуль из графа сборки
  • tree-shaking работает только внутри включённых модулей

Если модуль объявлен внешним:

  • его внутренние экспорты не анализируются
  • оптимизация кода не применяется

Это означает, что неправильное использование external может привести к потере оптимизаций.


Глобальные переменные и имена (output.name)

Для UMD и IIFE важно также поле:

output: {
  format: 'umd',
  name: 'MyLibrary'
}

Оно определяет:

  • имя глобальной переменной для самой библиотеки
  • контейнер, в который она будет помещена

В результате:

window.MyLibrary

становится точкой доступа к модулю.


Сложные маппинги в globals

globals не ограничивается простыми строками:

globals: {
  react: 'React',
  'react-dom': 'ReactDOM',
  'react/jsx-runtime': 'ReactJSXRuntime'
}

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


Ошибки при работе с globals

Несовпадение имени глобальной переменной

Если указано:

globals: {
  react: 'React'
}

но в браузере React подключён как:

window.ReactJS

возникает runtime error.


Забытый external

Если указать globals, но не добавить зависимость в external:

  • Rollup попытается встроить модуль
  • globals не будет использоваться
  • возможны конфликты и дублирование кода

Использование ESM без globals

В форматах esm поле globals игнорируется. Это частая причина путаницы при миграции между форматами сборки.


Взаимодействие с peerDependencies

В библиотечной разработке часто используется правило:

  • зависимости в peerDependencies → также добавляются в external
  • затем маппятся в globals для UMD

Пример:

"peerDependencies": {
  "react": ">=18"
}
external: ['react'],
output: {
  globals: {
    react: 'React'
  }
}

Это гарантирует, что:

  • React не дублируется
  • версия контролируется приложением
  • библиотека остаётся совместимой

Итоговая архитектурная модель

Комбинация external и globals формирует один из ключевых механизмов Rollup:

  • управление границей между бандлом и окружением
  • контроль дублирования зависимостей
  • обеспечение совместимости форматов UMD/IIFE
  • интеграция с CDN и глобальными библиотеками

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