this.getModuleInfo и this.getModuleIds

Контекст плагина Rollup формируется через объект this, доступный внутри большинства хуков. Он представляет собой API сборщика, через которое плагин получает доступ к графу модулей, метаданным и внутреннему состоянию бандла. Среди наиболее важных методов этого контекста выделяются this.getModuleInfo и this.getModuleIds, позволяющие работать с уже построенной структурой зависимостей.

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

Метаданные формируются по мере прохождения стадий пайплайна: resolveId, load, transform, moduleParsed, и становятся стабильно доступны в фазах, где граф уже частично или полностью построен.

this.getModuleInfo: доступ к метаданным модуля

Метод this.getModuleInfo(id) возвращает объект с информацией о конкретном модуле по его идентификатору.

Общая сигнатура

const info = this.getModuleInfo(id);

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

Структура ModuleInfo

Объект информации о модуле обычно содержит следующие поля:

  • id — уникальный идентификатор модуля (абсолютный путь или виртуальный ID)
  • importedIds — список статических импортов
  • dynamicImporters — модули, которые импортируют текущий модуль динамически
  • importers — статические импортеры
  • isEntry — является ли модуль точкой входа
  • isExternal — помечен ли модуль как внешний
  • hasModuleSideEffects — наличие побочных эффектов
  • ast — AST дерева (если включено и доступно)
  • meta — пользовательские метаданные, добавляемые плагинами
  • syntheticNamedExports — флаг синтетических экспортов

Структура может расширяться в зависимости от версии Rollup и активных плагинов, поскольку meta является расширяемым пространством.

Особенности доступности данных

this.getModuleInfo не гарантирует наличие полной информации на всех этапах сборки. Поведение зависит от стадии:

  • В resolveId модуль может отсутствовать в графе
  • В load информация может быть частичной
  • В transform большинство модулей уже присутствуют
  • В generateBundle граф полностью сформирован

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

Стабильность объекта

Возвращаемый объект является кэшированным представлением. Rollup не создает новый объект при каждом вызове, а возвращает ссылку на внутреннюю структуру. Это важно для оптимизации: повторные вызовы getModuleInfo не приводят к пересборке или повторному анализу.

Пример использования анализа зависимостей

export default function myPlugin() {
  return {
    name: 'dependency-analyzer',

    transform(code, id) {
      const info = this.getModuleInfo(id);

      if (!info) return;

      const hasDynamicImports = info.dynamicImporters.length > 0;

      if (hasDynamicImports) {
        this.warn(`Модуль ${id} используется в dynamic import`);
      }
    }
  };
}

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

Использование для обхода графа

getModuleInfo часто используется для рекурсивного обхода зависимостей:

function collectImports(pluginContext, id, result = new Set()) {
  const info = pluginContext.getModuleInfo(id);
  if (!info) return result;

  for (const imported of info.importedIds) {
    if (!result.has(imported)) {
      result.add(imported);
      collectImports(pluginContext, imported, result);
    }
  }

  return result;
}

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

Ограничения getModuleInfo

Несмотря на гибкость, метод имеет ряд ограничений:

  • не гарантирует наличие AST без соответствующих настроек
  • может возвращать null для еще не обработанных модулей
  • не предназначен для модификации графа
  • не отражает состояние до завершения стадии загрузки

Из-за этого его использование должно быть привязано к пониманию жизненного цикла сборки.

this.getModuleIds: доступ ко всем модулям графа

Метод this.getModuleIds() возвращает список всех модулей, которые были зарегистрированы в текущем графе сборки.

Сигнатура

for (const id of this.getModuleIds()) {
  // обработка модулей
}

Результатом является итерируемая коллекция идентификаторов модулей.

Особенности поведения

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

Ключевые характеристики:

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

Сравнение с getModuleInfo

Различие между методами принципиальное:

  • getModuleInfo(id) — доступ к одному узлу графа
  • getModuleIds() — доступ ко всему набору узлов

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

Пример обхода всего графа

export default function graphPlugin() {
  return {
    name: 'graph-plugin',

    generateBundle() {
      const stats = {
        totalModules: 0,
        entryModules: 0
      };

      for (const id of this.getModuleIds()) {
        const info = this.getModuleInfo(id);

        if (!info) continue;

        stats.totalModules++;

        if (info.isEntry) {
          stats.entryModules++;
        }
      }

      this.info(
        `Modules: ${stats.totalModules}, Entries: ${stats.entryModules}`
      );
    }
  };
}

Этот код демонстрирует глобальный анализ графа в момент генерации бандла.

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

На практике оба метода используются совместно. Типичный паттерн — сначала получить список всех модулей через getModuleIds, затем для каждого извлечь детальную информацию через getModuleInfo.

Такой подход обеспечивает:

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

Стадии сборки и доступность данных

Поведение методов тесно связано с пайплайном Rollup:

Фаза построения графа

  • модули постепенно добавляются
  • getModuleIds неполный
  • getModuleInfo частично доступен

Фаза трансформации

  • граф стабилизируется
  • метаданные становятся полнее
  • большинство зависимостей уже известны

Фаза генерации бандла

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

Метаданные и расширение через meta

Поле meta внутри ModuleInfo служит для обмена данными между плагинами. Оно не имеет строгой схемы и позволяет хранить произвольные структуры.

Пример:

transform(code, id) {
  const info = this.getModuleInfo(id);

  if (info) {
    info.meta.myPlugin = {
      analyzed: true,
      timestamp: Date.now()
    };
  }
}

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

Производительность и рекомендации по использованию

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

Оптимизационные особенности:

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

При работе с большими монорепозиториями важным становится ограничение количества полных обходов графа и агрегация данных в одной фазе.

Использование в watch-режиме

В режиме наблюдения граф модулей может изменяться между итерациями сборки. В этом случае:

  • getModuleIds отражает текущее состояние после пересборки
  • getModuleInfo обновляется при изменении модуля
  • кэш может инвалидироваться частично

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

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

  • анализ циклических зависимостей через обход импортов
  • построение dependency graph для визуализации
  • вычисление критического пути модулей
  • анализ влияния entry points
  • оптимизация code splitting
  • сбор статистики по проекту

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