Файл stats.json — это подробный отчёт Webpack о процессе
сборки проекта. Он содержит информацию о:
stats.json используется для:
Базовый способ генерации:
webpack --profile --json > stats.json
Либо:
npx webpack --json > stats.json
Для production-сборки:
npx webpack --mode production --json > stats.json
Через конфигурацию:
module.exports = {
stats: 'verbose'
};
Или программно:
const webpack = require('webpack');
const config = require('./webpack.config');
webpack(config, (err, stats) => {
require('fs').writeFileSync(
'stats.json',
JSON.stringify(stats.toJson(), null, 2)
);
});
Типичный файл состоит из следующих разделов:
{
"hash": "...",
"version": "5.x.x",
"time": 3456,
"builtAt": 1712345678901,
"publicPath": "auto",
"outputPath": "/dist",
"assets": [],
"chunks": [],
"modules": [],
"entrypoints": {},
"namedChunkGroups": {}
}
Основной интерес представляют:
assetschunksmodulesentrypointsnamedChunkGroupsРаздел assets описывает итоговые файлы сборки.
Пример:
{
"assets": [
{
"name": "main.js",
"size": 452331,
"emitted": true,
"cached": false,
"chunkNames": ["main"]
}
]
}
Имя итогового файла:
"name": "vendors.js"
Размер файла в байтах:
"size": 854331
Размер показывает:
Показывает, был ли файл реально записан на диск:
"emitted": true
Если файл не изменился:
"emitted": false
Файл взят из кеша:
"cached": true
Список chunk name:
"chunkNames": ["main"]
Дополнительная информация:
"info": {
"minimized": true
}
chunks описывает логические части бандла.
Пример:
{
"chunks": [
{
"id": 179,
"names": ["vendors"],
"files": ["vendors.js"],
"entry": false,
"initial": true,
"modules": []
}
]
}
Chunk — это группа модулей, объединённых Webpack.
Chunk может представлять:
Уникальный идентификатор:
"id": 179
Имя chunk:
"names": ["main"]
Файлы, связанные с chunk:
"files": [
"main.js"
]
Является ли chunk entry point:
"entry": true
Загружается ли chunk сразу:
"initial": true
Если:
"initial": false
значит chunk асинхронный.
Был ли chunk реально сгенерирован:
"rendered": true
Размер chunk:
"size": 945122
Связанные chunks:
"siblings": [23, 24]
Родительские chunks:
"parents": [1]
Дочерние chunks:
"children": [45]
Наиболее важный раздел.
Именно здесь анализируются:
Пример:
{
"modules": [
{
"name": "./src/index.js",
"size": 532,
"chunks": [179],
"issuer": null,
"reasons": []
}
]
}
Путь к модулю:
"name": "./src/components/Button.js"
Размер модуля:
"size": 14221
Это размер до минификации.
Chunks, в которые попал модуль:
"chunks": [179]
Кто импортировал модуль:
"issuer": "./src/index.js"
Это одно из ключевых полей для анализа цепочек зависимостей.
Полный путь импорта:
"issuerPath": [
{
"name": "./src/index.js"
},
{
"name": "./src/app.js"
}
]
Позволяет понять:
Причины включения модуля.
Пример:
"reasons": [
{
"type": "harmony import specifier",
"userRequest": "./Button"
}
]
reasons особенно важен при поиске:
Пример:
{
"type": "cjs require",
"userRequest": "lodash"
}
Это означает:
ES Modules импорт:
"type": "harmony import"
CommonJS require:
"type": "cjs require"
Динамический импорт:
"type": "import()"
Модуль является entry point:
"type": "entry"
Одна из главных задач — поиск тяжёлых модулей.
Пример:
{
"name": "./node_modules/moment/moment.js",
"size": 329122
}
Это сигнал:
Очень тяжёлые locale-файлы.
Импорт всей библиотеки:
import _ fr om 'lodash';
вместо:
import debounce fr om 'lodash/debounce';
Крупная визуализационная библиотека.
Огромный редактор кода.
date-fns обычно значительно меньше.
Webpack может удалять неиспользуемый код.
В stats.json это видно через:
usedExportsprovidedExportsoptimizationBailoutКакие exports реально используются:
"usedExports": ["debounce"]
Если:
"usedExports": false
значит tree shaking не сработал.
Какие exports предоставляет модуль:
"providedExports": [
"map",
"filter",
"reduce"
]
Причины отказа оптимизации:
"optimizationBailout": [
"CommonJS bailout: module.exports is used directly"
]
Это крайне важный раздел.
"CommonJS bailout"
ESM оптимизируются лучше.
"ModuleConcatenation bailout"
"Cannot determine exports"
Webpack не может безопасно анализировать модуль.
При использовании:
optimization: {
splitChunks: {
chunks: 'all'
}
}
в stats.json появляются:
Проверяются:
{
"name": "vendors-node_modules_react-dom_index_js.js",
"size": 2400000
}
Огромный vendor chunk ухудшает:
Иногда одна библиотека попадает в сборку несколько раз.
Пример:
{
"name": "./node_modules/lodash/lodash.js",
"chunks": [1]
}
и:
{
"name": "./node_modules/lodash-es/lodash.js",
"chunks": [5]
}
или разные версии:
node_modules/react
node_modules/some-lib/node_modules/react
Это увеличивает:
Раздел:
"entrypoints": {
"main": {
"assets": [
{
"name": "main.js"
}
]
}
}
показывает:
Показывает группы chunk.
Особенно важно при:
Пример:
"namedChunkGroups": {
"main": {
"chunks": [179]
}
}
Поле:
"time": 3456
означает время сборки в миллисекундах.
Но более полезен детальный profiling.
Генерация:
webpack --profile --json > stats.json
После этого появляются:
profilefactorybuildingdependenciesПример:
"profile": {
"factory": 12,
"building": 342
}
Время создания модуля.
Время обработки loader’ами.
Большие значения обычно означают:
Пример проблемного модуля:
{
"name": "./src/app.ts",
"profile": {
"building": 5321
}
}
Причины:
Source maps сильно влияют на:
В stats.json можно увидеть рост:
Очень быстрый.
Очень медленный, но качественный.
Компромисс между скоростью и качеством.
При использовании:
import('./admin');
Webpack создаёт async chunk.
В stats.json:
{
"initial": false
}
Необходимо убедиться:
При использовании:
splitChunks: {
cacheGroups: {
vendors: {
test: /node_modules/
}
}
}
в stats.json можно анализировать:
Иногда встречаются orphan modules.
Это модули:
Webpack учитывает:
"sideEffects": false
в package.json.
Это влияет на tree shaking.
{
"sideEffects": false
}
Позволяет удалять:
size обычно показывает размер до:
Например:
"chunks": [1, 5, 8]
Большой chunk не всегда проблема.
Иногда:
делают крупный vendor bundle допустимым.
Сортировка по:
"size"
Проверяются:
Поиск:
Анализируются:
usedExports;optimizationBailout;Проверяется:
Самый популярный инструмент.
Показывает:
Простой визуальный анализ.
Анализ времени loader’ов и plugins.
Глубокий анализ Webpack internals.
Предположим:
{
"name": "main.js",
"size": 8400000
}
Дальнейший анализ показывает:
{
"name": "./node_modules/moment/locale",
"size": 1200000
}
и:
{
"optimizationBailout": [
"CommonJS bailout"
]
}
Выводы:
В stats.json присутствуют:
"warnings": []
Часто встречаются:
Пример:
"asset size limit"
Webpack предупреждает о слишком крупном asset.
Слишком тяжёлый initial entrypoint.
Раздел:
"errors": []
может содержать:
Development stats часто:
Анализировать необходимо production build.
Webpack 5 добавляет runtime modules.
Пример:
{
"moduleType": "runtime"
}
Они отвечают за:
При scope hoisting:
"modules": [
{
"modules": []
}
]
Webpack объединяет несколько модулей в один.
Это улучшает:
Если scope hoisting не сработал:
"ModuleConcatenation bailout"
Причины:
При:
optimization: {
runtimeChunk: 'single'
}
в stats.json появляется отдельный runtime chunk.
Это улучшает: