Анализ размера модулей

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

Модуль в Webpack представляет отдельный файл или логическую единицу кода, включённую в граф зависимостей. Каждый модуль получает идентификатор, исходный путь, список зависимостей и вклад в итоговые чанки. Размер модуля в контексте сборки не всегда равен размеру исходного файла: трансформации Babel, минификация, tree-shaking и объединение кода изменяют итоговую величину.

Чанк объединяет множество модулей в единицу загрузки. Ассет является финальным файлом, который создаётся на выходе (например, .js или .css). Именно ассеты доставляются в браузер, поэтому анализ размера всегда должен учитывать цепочку «модуль → чанк → ассет».

Источники данных для анализа размера

Основой анализа выступает stats.json, формируемый Webpack при включении параметра статистики:

  • webpack --json > stats.json
  • stats: 'normal' | 'verbose' | 'detailed'

Внутри статистики ключевыми структурами являются:

  • modules — список модулей с информацией о размере и зависимости
  • chunks — распределение модулей по чанкам
  • assets — итоговые файлы и их размеры
  • entrypoints — точки входа и их состав
  • children — вложенные компиляции (например, при MultiCompiler)

Размер модуля в статистике представлен несколькими метриками:

  • size — исходный размер
  • built — результат обработки loader’ами
  • codeGenerated — итог после генерации кода

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

Инструменты визуализации и интерпретации

Анализ числовых данных из stats.json затруднён без визуализации. Используются специализированные инструменты:

  • webpack-bundle-analyzer — строит интерактивное дерево модулей с отображением вкладов в размер
  • source-map-explorer — анализирует итоговые source map и показывает реальный вклад исходных файлов
  • size-plugin — фиксирует изменения размера при каждой сборке
  • bundle-stats — сравнение размеров между сборками

webpack-bundle-analyzer опирается на stats.json и отображает иерархию:

  • entrypoint

    • chunk

      • module

        • dependency chain

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

Интерпретация графа модулей

Граф модулей представляет собой ориентированный ациклический граф, где вершины — модули, а рёбра — зависимости import/require.

Анализ размера в этом графе включает:

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

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

Tree Shaking и влияние на размер модулей

Tree shaking опирается на статический анализ ES Modules. Включение механизма происходит через:

  • optimization.usedExports: true
  • mode: production

Webpack помечает экспортируемые символы как используемые или неиспользуемые. При корректной конфигурации неиспользуемый код удаляется на этапе Terser.

Эффективность tree shaking зависит от:

  • формата модулей (ESM предпочтительнее CommonJS)
  • отсутствия побочных эффектов
  • структуры экспорта

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

Side Effects и влияние на размер

Флаг sideEffects в package.json влияет на возможность удаления кода:

  • false — весь модуль считается безопасным для удаления неиспользуемых частей
  • массив путей — частичная защита файлов с побочными эффектами

При отсутствии корректного sideEffects Webpack сохраняет модули целиком, увеличивая итоговый размер чанков.

Особенно критично это для библиотек с CSS, polyfills и глобальными регистрациями.

Scope Hoisting и Module Concatenation

Module Concatenation Plugin объединяет модули в единый контекст исполнения, уменьшая накладные расходы обёрток:

  • снижает количество функций-обёрток
  • уменьшает runtime overhead
  • повышает эффективность минификации

Влияние на размер выражается не только в уменьшении байтов, но и в улучшении compressibility (gzip/brotli).

Разбиение чанков и влияние на размер

splitChunks напрямую влияет на распределение размеров:

  • общие зависимости выносятся в отдельные чанки
  • vendor-код отделяется от application-кода
  • динамические импорты создают lazy chunks

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

  • splitChunks.cacheGroups
  • splitChunks.chunks
  • splitChunks.minSize
  • splitChunks.maxInitialRequests

Ошибочная настройка приводит к:

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

Динамические импорты и ленивые чанки

import() создаёт отдельные чанки, влияющие на распределение размера. В анализе это проявляется как:

  • уменьшение initial bundle
  • рост количества async chunks
  • перераспределение тяжёлых модулей

Размер модуля в async chunk не исчезает, но переносится из критического пути загрузки в отложенную загрузку.

Поиск тяжёлых зависимостей

Типовые источники увеличения размера:

  • UI-библиотеки с полной загрузкой (lodash без tree-shaking, moment.js)
  • полные polyfill-бандлы
  • неразделённые иконки и графика
  • дублирование зависимостей через разные версии пакетов

Анализ включает проверку:

  • повторяющихся модулей в разных чанках
  • альтернативных импортов (deep import vs root import)
  • фактического использования API

Дубликаты модулей

Дубликаты возникают при:

  • несовпадении версий зависимостей
  • разных путях импорта одной библиотеки
  • отсутствии hoisting в node_modules
  • монорепозиториях без dedupe

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

Performance hints и бюджет размера

Webpack поддерживает механизм ограничения размера:

  • performance.maxAssetSize
  • performance.maxEntrypointSize
  • performance.hints

При превышении порогов сборка выдаёт предупреждения, основанные на итоговых ассетах.

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

Влияние source maps на оценку размера

Source maps не влияют на production bundle, но искажают восприятие размера при анализе:

  • увеличивают общий объём файлов в dev-режиме
  • добавляют дополнительные модули в stats
  • могут скрывать фактический вклад кода при неправильной интерпретации

При анализе размеров используется production-сборка без source maps или с отдельным анализом через source-map-explorer.

Кэширование и стабильность размера

Использование contenthash влияет на стратегию анализа:

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

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

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

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

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

Корректная интерпретация требует сопоставления всех уровней, так как оптимизация на одном уровне может ухудшить другой (например, уменьшение chunk size увеличивает duplication).