dependOn и оптимизация общих чанков между entry

Разделение зависимостей между точками входа в Webpack напрямую связано с механизмом формирования общих чанков и управлением повторно используемым кодом. При наличии нескольких entry-поинтов неизбежно возникает ситуация, когда одни и те же модули импортируются в разных частях приложения. Без оптимизации это приводит к дублированию кода в результирующих бандлах, увеличению общего размера сборки и ухудшению кешируемости.

При классической конфигурации с несколькими точками входа Webpack строит отдельные графы зависимостей для каждого entry. Если оба графа содержат одинаковые импорты, например утилиты, библиотеки или shared-компоненты, то без дополнительных настроек эти зависимости будут включены в каждый бандл отдельно.

Типичный пример:

// entry-a.js
import { formatDate } from './utils/date';
import { apiRequest } from './utils/api';

console.log(formatDate(Date.now()));
apiRequest('/endpoint-a');

// entry-b.js
import { formatDate } from './utils/date';
import { apiRequest } from './utils/api';

console.log(formatDate(Date.now()));
apiRequest('/endpoint-b');

В данном случае модуль utils/date и utils/api оказываются в двух независимых чанках. Это приводит к:

  • дублированию кода в итоговой сборке
  • увеличению времени загрузки
  • невозможности эффективно использовать HTTP-кэш между страницами

Роль optimization.splitChunks

Основным механизмом устранения дублирования является optimization.splitChunks. Именно он отвечает за анализ графа модулей и выделение общих зависимостей в отдельные чанки.

Базовая конфигурация:

module.exports = {
  entry: {
    pageA: './src/entry-a.js',
    pageB: './src/entry-b.js'
  },
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  }
};

Параметр chunks: 'all' включает анализ как синхронных, так и асинхронных зависимостей. В результате Webpack автоматически выделяет общий код в отдельный chunk, который подключается к обоим entry.

Логика формирования общих чанков

Webpack использует внутренние эвристики для определения “общности” модуля:

  • модуль должен присутствовать минимум в двух чанках
  • учитывается порог размера
  • учитывается тип загрузки (initial или async)
  • анализируется частота использования

После анализа формируется отдельный chunk, обычно именуемый автоматически (например, vendors~pageA~pageB.js).

Поведение без явного shared-конфигура

Если splitChunks не настроен, Webpack не гарантирует извлечение общего кода. В этом случае каждая entry-секция становится полностью независимой единицей сборки. Это поведение может быть допустимо только для очень маленьких приложений или специальных случаев, где изоляция важнее оптимизации.

Ограничения базового разделения

Автоматическое разделение не всегда даёт оптимальный результат:

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

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

Cache Groups и контроль shared-кода

Механизм cacheGroups позволяет задавать правила группировки модулей:

module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        shared: {
          name: 'shared',
          minChunks: 2,
          priority: 10,
          reuseExistingChunk: true
        }
      }
    }
  }
};

Здесь:

  • minChunks: 2 гарантирует, что модуль должен встречаться минимум в двух местах
  • reuseExistingChunk предотвращает дублирование уже выделенных модулей
  • priority управляет конфликтами между группами

Влияние dependOn на архитектуру entry

Параллельно с splitChunks Webpack предоставляет механизм dependOn, который позволяет явно выразить зависимость одной точки входа от другой. Это не автоматическая оптимизация, а декларативное управление графом entry.

Пример:

module.exports = {
  entry: {
    shared: './src/shared.js',
    pageA: {
      import: './src/page-a.js',
      dependOn: 'shared'
    },
    pageB: {
      import: './src/page-b.js',
      dependOn: 'shared'
    }
  }
};

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

  • entry shared загружается один раз
  • pageA и pageB используют его как базовый слой
  • Webpack исключает дублирование модулей, уже входящих в shared

Отличие dependOn от splitChunks

Несмотря на схожую цель — устранение дублирования — механизмы принципиально различаются.

dependOn:

  • работает на уровне entry-конфигурации
  • требует явного указания зависимостей
  • формирует предсказуемую структуру бандлов
  • подходит для multi-page приложений с фиксированной архитектурой

splitChunks:

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

Комбинирование dependOn и splitChunks

На практике оба механизма могут использоваться совместно. dependOn задаёт архитектурный каркас, а splitChunks оптимизирует вторичные пересечения.

Пример комбинированной схемы:

module.exports = {
  entry: {
    vendor: './src/vendor.js',
    appA: {
      import: './src/app-a.js',
      dependOn: 'vendor'
    },
    appB: {
      import: './src/app-b.js',
      dependOn: 'vendor'
    }
  },
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  }
};

В этой модели:

  • vendor содержит стабильные библиотеки
  • splitChunks дополнительно извлекает пересечения между appA и appB
  • уменьшается вероятность дублирования даже при частичном совпадении зависимостей

Поведение runtime при dependOn

При использовании dependOn Webpack корректирует runtime таким образом, чтобы:

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

Это особенно важно при наличии side effects в модулях, так как порядок загрузки становится детерминированным.

Типичные ошибки при организации shared entry

Одной из распространённых проблем является чрезмерное дробление entry-поинтов. Когда разработчик выносит слишком много логики в dependOn, структура сборки становится жёсткой и плохо масштабируемой.

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

Приоритеты и взаимодействие механизмов

Webpack всегда применяет следующий порядок логики:

  1. обработка entry и dependOn
  2. построение графа модулей
  3. применение splitChunks
  4. генерация runtime-кода

Это означает, что dependOn формирует базовую структуру, а splitChunks уже оптимизирует её поверх.

Практическая модель организации shared-кода

Наиболее устойчивый подход к многоточечной сборке заключается в следующей структуре:

  • отдельный entry для стабильных зависимостей (polyfills, frameworks)
  • entry-поинты для страниц или модулей приложения
  • splitChunks для динамического выделения пересечений

Такая комбинация позволяет:

  • минимизировать дублирование
  • улучшить кеширование между страницами
  • сохранить предсказуемую архитектуру
  • снизить стоимость поддержки сборки

Механизмы dependOn и splitChunks в совокупности формируют основу управления повторно используемым кодом в Webpack и позволяют контролировать баланс между автоматической оптимизацией и явной архитектурной структурой.