Автоматический code splitting при наличии нескольких точек входа

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

Модель работы Rollup при нескольких entry points

Когда в конфигурации указывается массив или объект точек входа, Rollup строит единый граф зависимостей для всех указанных модулей. Вместо независимой сборки каждого entry point происходит анализ пересечений:

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

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

Пример конфигурации:

export default {
  input: {
    main: 'src/main.js',
    admin: 'src/admin.js'
  },
  output: {
    dir: 'dist',
    format: 'esm'
  }
};

В этом случае Rollup анализирует оба входных файла и их зависимости как единый граф.

Автоматическое выделение общих модулей

При наличии пересечений между графами зависимостей Rollup создаёт отдельные чанки. Например, если оба entry point используют один и тот же модуль:

// src/utils/math.js
export function sum(a, b) {
  return a + b;
}

И он импортируется в разных точках входа:

// src/main.js
import { sum } from './utils/math.js';
console.log(sum(2, 3));
// src/admin.js
import { sum } from './utils/math.js';
console.log(sum(10, 20));

Rollup извлечёт math.js в отдельный chunk, если формат вывода поддерживает динамическую загрузку (например, esm).

Условия активации code splitting

Автоматическое разделение кода при нескольких entry points работает только при выполнении ряда условий:

1. Используется формат ES modules

Code splitting поддерживается только для форматов, допускающих динамическую загрузку:

  • esm
  • system (частично, через плагины)

Форматы cjs и iife не поддерживают разбиение на чанки, так как предполагают единый исполняемый файл.

2. Включена директория output

При использовании code splitting требуется указание директории вместо файла:

output: {
  dir: 'dist',
  format: 'esm'
}

Попытка использовать file приведёт к ошибке, поскольку несколько чанков невозможно упаковать в один файл.

3. Отсутствие ограничений на синхронизацию графа

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

Алгоритм формирования чанков

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

  1. Построение полного dependency graph для всех entry points.

  2. Определение strongly connected components.

  3. Выделение shared modules.

  4. Формирование чанков на основе:

    • уникальных цепочек зависимостей;
    • общих модулей;
    • динамических импортов (если присутствуют).

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

Поведение при частичном пересечении зависимостей

Рассмотрим структуру:

main.js → a.js → shared.js
admin.js → b.js → shared.js

В этом случае shared.js будет вынесен в отдельный chunk. Остальные модули останутся в своих цепочках.

Если же зависимость используется только в одном entry point, она не выносится отдельно и остаётся внутри соответствующего чанка.

Влияние динамических импортов

Хотя основная тема связана с множественными entry points, поведение code splitting усиливается при использовании import():

// src/main.js
button.oncl ick = async () => {
  const module = await import('./heavy-module.js');
  module.run();
};

В таком случае Rollup:

  • создаёт отдельный async chunk для heavy-module.js;
  • учитывает его при анализе графа entry points;
  • может объединять его с другими динамическими зависимостями.

При сочетании нескольких entry points и динамических импортов формируется гибридная структура чанков.

Конфигурационные особенности

Для корректной работы разделения кода часто требуется дополнительная настройка:

manualChunks

Позволяет управлять логикой разбиения вручную:

output: {
  dir: 'dist',
  format: 'esm',
  manualChunks(id) {
    if (id.includes('node_modules')) {
      return 'vendor';
    }
  }
}

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

preserveModules

При включении этого режима Rollup сохраняет структуру исходных модулей:

output: {
  dir: 'dist',
  format: 'esm',
  preserveModules: true
}

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

Поведение с внешними зависимостями

External зависимости исключаются из графа и не участвуют в code splitting:

external: ['lodash']

При нескольких entry points такие зависимости остаются ссылочными и не влияют на формирование чанков.

Типичные сценарии использования нескольких entry points

Многостраничные приложения

Каждая страница имеет собственный entry point, но использует общий набор утилит и компонентов.

Административная и публичная части

Разделение admin и client с частично пересекающейся бизнес-логикой.

Библиотеки с несколькими точками экспорта

Каждый entry point соответствует отдельной функциональной зоне API.

Ограничения модели

Автоматическое code splitting при нескольких entry points имеет ряд ограничений:

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

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