SplitChunksPlugin: автоматическое выделение общих зависимостей

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

Принцип работы механизма разделения

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

SplitChunksPlugin анализирует этот граф и принимает решение о том, какие модули:

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

После анализа создаются новые чанки, содержащие общие зависимости, а исходные чанки переподключаются через runtime-обвязку Webpack.

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

Настройка осуществляется через optimization.splitChunks:

module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  }
}

Значение chunks: 'all' включает анализ как синхронных, так и асинхронных импортов, что делает поведение наиболее агрессивным с точки зрения выделения общего кода.

Другие варианты:

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

Ключевые параметры SplitChunksPlugin

minSize

Определяет минимальный размер модуля или группы модулей для выделения в отдельный чанк.

splitChunks: {
  minSize: 20000
}

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

minChunks

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

splitChunks: {
  minChunks: 2
}

Если модуль используется только один раз, он остаётся внутри исходного чанка.

maxAsyncRequests и maxInitialRequests

Ограничивают количество параллельных загрузок:

splitChunks: {
  maxAsyncRequests: 30,
  maxInitialRequests: 30
}

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

name

Позволяет задавать имя создаваемого чанка.

splitChunks: {
  name: 'common'
}

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

cacheGroups: основа логики разделения

Основной механизм управления поведением SplitChunksPlugin реализован через cacheGroups. Это набор правил, определяющих, какие модули и куда выносить.

splitChunks: {
  cacheGroups: {
    vendors: {
      test: /[\\/]node_modules[\\/]/,
      name: 'vendors',
      chunks: 'all'
    }
  }
}

В этом примере все зависимости из node_modules собираются в отдельный чанк vendors.

Структура cacheGroups

Каждая группа может содержать:

  • test — фильтр модулей (регулярное выражение или функция)
  • name — имя чанка
  • chunks — тип чанков (async, initial, all)
  • priority — приоритет применения правил
  • enforce — принудительное применение без учёта глобальных ограничений
  • reuseExistingChunk — переиспользование существующего чанка

Приоритеты cacheGroups

Если модуль подходит под несколько правил, используется параметр priority.

splitChunks: {
  cacheGroups: {
    vendor: {
      test: /node_modules/,
      name: 'vendor',
      priority: 10
    },
    common: {
      test: /src/,
      name: 'common',
      priority: 5
    }
  }
}

Модуль из node_modules попадёт в vendor, так как у него более высокий приоритет.

Выделение общего кода приложения

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

splitChunks: {
  cacheGroups: {
    common: {
      minChunks: 2,
      chunks: 'all',
      name: 'common',
      enforce: true
    }
  }
}

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

Разделение vendor-кода

Часто используется стратегия отделения сторонних библиотек:

splitChunks: {
  cacheGroups: {
    vendors: {
      test: /[\\/]node_modules[\\/]/,
      name: 'vendors',
      chunks: 'all',
      enforce: true
    }
  }
}

Это улучшает кэширование, так как зависимости из node_modules изменяются значительно реже, чем код приложения.

Поведение chunks: async, initial, all

Различие режимов влияет на стратегию загрузки:

  • async — оптимизация только для динамических импортов
  • initial — влияет на основной entry bundle
  • all — объединяет оба режима и обеспечивает максимальное разделение

Пример динамического разделения:

import('lodash').then(({ default: _ }) => {
  console.log(_.chunk([1, 2, 3], 2));
});

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

reuseExistingChunk

Оптимизация повторного использования уже созданных чанков:

splitChunks: {
  cacheGroups: {
    common: {
      reuseExistingChunk: true
    }
  }
}

Если модуль уже выделен в отдельный чанк, Webpack не создаёт дубликат, а подключает существующий.

enforce: принудительное создание чанка

Параметр enforce отключает часть глобальных ограничений (minSize, minChunks):

splitChunks: {
  cacheGroups: {
    largeLib: {
      test: /large-library/,
      name: 'large-lib',
      enforce: true
    }
  }
}

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

Алгоритм принятия решений SplitChunksPlugin

Поведение можно описать последовательностью шагов:

  1. Анализ всех модулей в графе зависимостей
  2. Проверка соответствия cacheGroups
  3. Оценка minChunks и minSize
  4. Проверка ограничений maxInitialRequests и maxAsyncRequests
  5. Выбор группы с наивысшим приоритетом
  6. Создание нового чанка или использование существующего
  7. Переподключение модулей через runtime Webpack

Типичные стратегии использования

Базовая стратегия для приложений

splitChunks: {
  chunks: 'all',
  cacheGroups: {
    vendors: {
      test: /node_modules/,
      name: 'vendors'
    },
    common: {
      minChunks: 2,
      name: 'common'
    }
  }
}

Стратегия для крупных SPA

splitChunks: {
  chunks: 'all',
  minSize: 30000,
  cacheGroups: {
    react: {
      test: /react|react-dom/,
      name: 'react',
      priority: 20
    },
    vendors: {
      test: /node_modules/,
      name: 'vendors',
      priority: 10
    },
    common: {
      minChunks: 2,
      name: 'common',
      priority: 5
    }
  }
}

Стратегия агрессивного кэширования

splitChunks: {
  chunks: 'all',
  maxInitialRequests: 20,
  maxAsyncRequests: 30,
  cacheGroups: {
    vendors: {
      test: /node_modules/,
      name(module) {
        const match = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/);
        return match ? match[1] : 'vendors';
      }
    }
  }
}

В этом случае каждая библиотека может быть вынесена в отдельный чанк для максимального кэширования.

Связь SplitChunksPlugin и runtime Webpack

После выделения чанков Webpack генерирует runtime-код, который отвечает за:

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

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

Особенности работы с динамическими импортами

import() является естественной точкой разделения кода, но SplitChunksPlugin может дополнительно оптимизировать такие чанки:

  • объединять общие зависимости нескольких динамических импортов
  • выделять shared-модули между async chunks
  • уменьшать дублирование библиотек

Частые ошибки конфигурации

Слишком маленький minSize

Приводит к созданию множества мелких файлов, что увеличивает количество HTTP-запросов и ухудшает производительность.

Отсутствие cacheGroups

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

Чрезмерное дробление vendors

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

Игнорирование maxInitialRequests

Большое количество initial чанков может замедлить загрузку главной страницы.

Влияние на кэширование браузера

SplitChunksPlugin напрямую влияет на эффективность долгосрочного кэширования:

  • vendor-чанки меняются редко → высокий cache hit ratio
  • common-чанки стабильны между релизами
  • application chunks обновляются чаще, но меньше по размеру

Правильное разделение снижает объём повторно загружаемых данных при обновлении приложения.

Производственные сценарии использования

В крупных проектах SplitChunksPlugin применяется совместно с:

  • code splitting через import()
  • долгосрочным хэшированием [contenthash]
  • предзагрузкой (prefetch, preload)
  • анализом бандла (webpack-bundle-analyzer)

Такая комбинация позволяет выстраивать структуру сборки, в которой:

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