Отличие сборки библиотеки от сборки приложения

Сборка библиотеки и сборка приложения решают принципиально разные задачи, несмотря на использование схожих инструментов и конфигураций сборщиков. В контексте Rollup это различие проявляется особенно явно, поскольку инструмент изначально ориентирован на создание библиотек с максимально чистым и предсказуемым итоговым бандлом.

Сборка приложения ориентирована на выполнение конкретной бизнес-логики в рамках одного окружения. Итоговый бандл обычно обслуживает единственный продукт, тесно связан с инфраструктурой проекта и предполагает полный контроль над зависимостями и средой исполнения.

Сборка библиотеки направлена на повторное использование кода в различных проектах. Это накладывает ограничения на структуру выходного кода, формат модулей и степень связанности с внешними зависимостями. Библиотека должна быть максимально нейтральной по отношению к окружению, в котором она будет использоваться.

Контроль зависимостей и внешние модули

В приложении зависимости, как правило, включаются в итоговый бандл. Это упрощает деплой и гарантирует, что нужные версии библиотек будут поставляться вместе с кодом.

В библиотечной сборке ключевую роль играет механизм external в Rollup. Он позволяет исключить зависимости из бандла и оставить их для разрешения в проекте-потребителе. Это особенно важно для:

  • react, vue, angular и других runtime-библиотек
  • утилитарных пакетов с peerDependencies
  • системных или больших зависимостей, которые должны быть разделяемыми

Типичная ошибка при сборке библиотек — включение всех зависимостей внутрь пакета. Это приводит к дублированию кода и конфликтам версий у потребителей.

Форматы выходного кода

Приложения чаще всего собираются в один формат, ориентированный на браузер или конкретную платформу. На практике это может быть ESM-бандл или IIFE-скрипт.

Библиотеки почти всегда требуют мультиформатной сборки:

  • ESM (ES Modules) — для современных сборщиков и tree-shaking
  • CJS (CommonJS) — для Node.js-экосистемы
  • UMD — для универсального использования через script-теги

Rollup позволяет формировать несколько output-конфигураций, каждая из которых должна учитывать особенности экспорта. Например, ESM сохраняет статическую структуру импортов, тогда как UMD требует глобального имени библиотеки.

Структура экспорта и публичное API

В приложениях внутренние модули не предназначены для повторного использования. Поэтому структура экспорта не является важным архитектурным контрактом.

В библиотеках публичное API становится центральным элементом архитектуры. Rollup в этом контексте часто используется вместе с:

  • явными entry-point файлами (index.js / index.ts)
  • ограничением экспортируемых сущностей через barrel-структуру
  • контролем side effects через package.json

Особое значение имеет сохранение предсказуемой структуры экспортов. Любое изменение публичного API рассматривается как breaking change.

Tree-shaking и чистота модулей

В приложениях tree-shaking часто вторичен, так как конечный бандл включает практически всю кодовую базу.

В библиотеках tree-shaking является критическим свойством. Rollup использует статический анализ импортов, что позволяет удалять неиспользуемый код, но только при соблюдении определённых условий:

  • отсутствие побочных эффектов в модулях
  • использование ES-модулей
  • корректная декларация sideEffects в package.json

Библиотечный код должен быть написан с учётом максимально «чистой» структуры модулей, где каждый экспорт не вызывает скрытых изменений состояния.

Code splitting и стратегия сборки

Приложения активно используют code splitting для оптимизации загрузки. Rollup в этом случае генерирует чанки, разделяя приложение по маршрутам или динамическим импортам.

Для библиотек code splitting, как правило, нежелателен. Итоговый пакет должен быть компактным и предсказуемым. В большинстве случаев используется:

  • единый входной файл
  • либо ограниченное количество entry points для разных частей API

Фрагментация библиотеки на множество чанков усложняет интеграцию и увеличивает накладные расходы у потребителя.

External dependencies и peerDependencies

В приложениях зависимости обычно фиксируются внутри сборки, а версия контролируется через lock-файлы.

В библиотеках ключевую роль играют peerDependencies. Они определяют, что конкретные зависимости должны предоставляться окружением. Rollup-конфигурация должна учитывать это через external, иначе возникает риск:

  • дублирования React или других runtime-библиотек
  • конфликтов версий
  • увеличения размера итогового бандла

Правильное разделение dependencies и peerDependencies становится архитектурным контрактом библиотеки.

UMD-глобалы и интеграция с окружением

При сборке библиотек в формате UMD требуется явное определение глобальных переменных. Rollup позволяет задать mapping внешних зависимостей через globals, чтобы обеспечить корректную работу в браузере без модульной системы.

В приложениях такая необходимость практически отсутствует, так как окружение заранее известно (например, Vite, Webpack или Node runtime).

Минификация и постобработка

В приложениях минификация направлена на уменьшение размера финального бандла и ускорение загрузки. Часто применяется агрессивное сжатие, включая удаление дебаг-логики.

В библиотеках подход более аккуратный:

  • важно сохранять читаемость для дебага пользователей
  • часто предоставляются две версии: minified и unminified
  • необходимо сохранять корректные sourcemap для интеграции в чужие проекты

Работа с побочными эффектами

Приложения допускают наличие глобального состояния и побочных эффектов, так как они управляются в рамках одного проекта.

В библиотеках побочные эффекты становятся критической проблемой. Rollup опирается на декларативную модель модулей, где:

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

Это влияет на способность библиотеки участвовать в tree-shaking и корректно комбинироваться с другими пакетами.

Различия в конфигурации Rollup

Конфигурация сборки приложения обычно проще:

  • один input
  • один output
  • минимальное количество плагинов

Библиотечная конфигурация значительно сложнее и часто включает:

  • несколько output targets (esm, cjs, umd)
  • external dependencies
  • генерацию типов (при использовании TypeScript)
  • разделение development и production сборок
  • контроль имен глобальных переменных

Дополнительно могут использоваться плагины для очистки кода, генерации деклараций и анализа размера бандла.

Версионирование и стабильность API

В приложениях версия бандла не является публичным контрактом — важна только текущая поставка.

В библиотеках версия становится частью API-контракта. Сборка должна учитывать:

  • семантическое версионирование
  • обратную совместимость
  • стабильность экспортируемых интерфейсов

Rollup в этом контексте выступает инструментом, обеспечивающим воспроизводимость артефакта, а не просто упаковку кода.

Итоговая разница архитектурных подходов

Различие между сборкой библиотеки и приложения в Rollup выражается не только в конфигурации, но и в философии:

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

Rollup в библиотечной сборке используется как инструмент строгой модульности, где важнее предсказуемость API и чистота зависимостей, чем агрессивная оптимизация под один конкретный сценарий выполнения.