Хук options

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

Хук options вызывается самым первым среди всех плагинных хуков. Он срабатывает до:

  • разрешения входных точек (input resolution)
  • выполнения buildStart
  • анализа модулей
  • трансформаций кода

Это делает его ключевым местом для вмешательства в конфигурацию сборки до того, как она станет фиксированной.

Важно учитывать, что на этом этапе:

  • граф модулей ещё не существует
  • плагины ещё не получили доступ к файлам проекта
  • никакие трансформации кода не выполняются

options работает исключительно с конфигурационным объектом.

Сигнатура и форма данных

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

Типичная форма:

export default function myPlugin() {
  return {
    name: 'my-plugin',

    options(inputOptions) {
      return inputOptions;
    }
  };
}

Аргумент inputOptions содержит:

  • input: входные точки
  • plugins: массив плагинов
  • external: настройки внешних зависимостей
  • treeshake: конфигурация tree-shaking
  • output: частично нормализованные опции вывода

Хук может вернуть:

  • модифицированный объект options
  • null или undefined (если изменений нет)
  • новый объект конфигурации, заменяющий текущий

Механизм модификации конфигурации

Основная задача options — вмешательство в конфигурацию до её фиксации. Это может включать:

Изменение входных точек

options(inputOptions) {
  return {
    ...inputOptions,
    input: {
      main: 'src/index.js',
      admin: 'src/admin.js'
    }
  };
}

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

Добавление или изменение плагинов

options(inputOptions) {
  return {
    ...inputOptions,
    plugins: [
      ...inputOptions.plugins,
      myInjectedPlugin()
    ]
  };
}

Это позволяет динамически расширять pipeline обработки.

Переконфигурация treeshaking

options(inputOptions) {
  return {
    ...inputOptions,
    treeshake: {
      moduleSideEffects: false,
      propertyReadSideEffects: false
    }
  };
}

На этом уровне изменения ещё не влияют на граф, но определяют стратегию оптимизации.

Асинхронное поведение

options может быть асинхронным:

options: async (inputOptions) => {
  const config = await loadExternalConfig();

  return {
    ...inputOptions,
    external: config.external
  };
}

Это делает возможным:

  • загрузку удалённых конфигураций
  • чтение файлов окружения
  • запросы к API перед сборкой

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

Приоритет и композиция плагинов

Если несколько плагинов реализуют options, они выполняются последовательно в порядке подключения.

Пример цепочки:

plugins: [
  pluginA(),
  pluginB(),
  pluginC()
]

Порядок выполнения:

  1. pluginA.options
  2. pluginB.options
  3. pluginC.options

Каждый следующий плагин получает результат предыдущего.

options(inputOptions) {
  const modified = pluginA(inputOptions);
  return pluginB(modified);
}

Это означает, что порядок подключения плагинов критически влияет на итоговую конфигурацию.

Влияние на build pipeline

options влияет на всю дальнейшую сборку, поскольку изменяет базовые параметры, используемые Rollup при инициализации:

  • input определяет граф модулей
  • plugins определяют трансформации
  • external влияет на исключение зависимостей
  • treeshake определяет стратегию удаления кода

Ошибки на этом этапе часто проявляются позже, в виде:

  • отсутствующих модулей
  • неожиданно исключённого кода
  • конфликтов плагинов
  • некорректной оптимизации

Мутация против иммутабельности

Хотя Rollup допускает возврат модифицированного объекта, прямое изменение входного аргумента может привести к трудноотлаживаемым эффектам.

Непредсказуемый вариант:

options(inputOptions) {
  inputOptions.input = 'src/new-entry.js';
  return inputOptions;
}

Более стабильный подход:

options(inputOptions) {
  return {
    ...inputOptions,
    input: 'src/new-entry.js'
  };
}

Иммутабельный стиль снижает риск конфликтов между плагинами.

Расширенные сценарии использования

Условная модификация конфигурации

options(inputOptions) {
  if (process.env.BUILD_TARGET === 'legacy') {
    return {
      ...inputOptions,
      treeshake: false
    };
  }

  return inputOptions;
}

Динамическое добавление входов

options(inputOptions) {
  const entries = Array.isArray(inputOptions.input)
    ? inputOptions.input
    : [inputOptions.input];

  return {
    ...inputOptions,
    input: [
      ...entries,
      'src/polyfills.js'
    ]
  };
}

Инъекция конфигурации окружения

options(inputOptions) {
  return {
    ...inputOptions,
    external: (id) => {
      return id.startsWith('node:') || id === 'fs';
    }
  };
}

Частые ошибки и ограничения

Попытка доступа к графу модулей

На этапе options граф ещё не существует, поэтому любые попытки анализа зависимостей невозможны.

Побочные эффекты

Любые операции с файловой системой или сетью увеличивают время старта сборки и могут приводить к нестабильности CI.

Неконсистентная модификация plugins массива

Если плагины добавляются без учёта порядка, возможны конфликты lifecycle-хуков.

Потеря исходной конфигурации

Полная замена объекта без spread-оператора приводит к потере важных параметров:

options() {
  return {
    input: 'src/index.js'
  };
}

Такой код уничтожает остальные настройки сборки.

Отличие от buildStart

Хотя options и buildStart часто используются вместе, их роли различаются:

  • options: изменение конфигурации до инициализации сборки
  • buildStart: реакция на уже готовую конфигурацию и старт процесса

options влияет на структуру сборки, buildStart — на поведение внутри неё.

Поведение при возврате null или undefined

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

options(inputOptions) {
  console.log('input:', inputOptions);
}

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

Композиция сложных плагинов

В крупных системах options часто используется как точка агрегации конфигурации:

  • объединение микрофронтендов
  • внедрение корпоративных стандартов сборки
  • автоматическая настройка production/dev режимов
  • подключение feature flags

В таких случаях options становится центральным механизмом нормализации конфигурации перед запуском сборки.