Метапредставление сборки (metafile) в esbuild представляет собой структурированный JSON-отчёт о процессе бандлинга, который фиксирует взаимосвязи между входными файлами, промежуточными модулями и финальными выходными артефактами. Его основная ценность заключается в возможности детально анализировать, как конфигурация сборщика влияет на результат, без необходимости вручную разбирать итоговый бандл.
Включение генерации метафайла выполняется явно, поскольку его
создание увеличивает объём работы сборщика. В Node.js API это задаётся
через параметр metafile: true, а в CLI — через флаг
--metafile.
import * as esbuild from 'esbuild';
await esbuild.build({
entryPoints: ['src/index.js'],
bundle: true,
outfile: 'dist/app.js',
metafile: true
});
При использовании CLI:
esbuild src/index.js --bundle --outfile=dist/app.js --metafile=meta.json
В CLI-режиме esbuild не только генерирует метафайл, но и сохраняет его в файл. В Node.js API он возвращается как часть результата сборки:
const result = await esbuild.build({
entryPoints: ['src/index.js'],
bundle: true,
metafile: true,
write: false
});
console.log(result.metafile);
Mетафайл представляет собой JSON-объект с несколькими ключевыми секциями, каждая из которых отражает отдельный аспект сборки.
Раздел inputs содержит все исходные модули, которые
участвовали в сборке. Каждый файл представлен как ключ, а его значение
описывает, как он использовался.
{
"inputs": {
"src/index.js": {
"bytes": 120,
"imports": [
{ "path": "./utils.js" },
{ "path": "react" }
]
}
}
}
Ключевые поля:
bytes — размер исходного файлаimports — список импортируемых зависимостейformat — информация о типе модуля (ESM/CJS)Раздел outputs описывает все итоговые бандлы, созданные
сборщиком.
{
"outputs": {
"dist/app.js": {
"bytes": 245000,
"inputs": {
"src/index.js": {},
"src/utils.js": {}
},
"imports": [
"react"
],
"exports": ["default"]
}
}
}
Здесь можно увидеть:
Одним из ключевых элементов анализа является поле
imports. Оно позволяет проследить цепочку зависимостей
вплоть до конечного бандла. Это особенно важно при диагностике случаев,
когда модуль неожиданно попал или не попал в сборку.
Metafile позволяет выявлять несоответствия между ожидаемым и фактическим поведением сборки. Типичные сценарии:
Если модуль не попал в бандл, его отсутствие можно отследить через
inputs и outputs. При корректной конфигурации
каждый используемый модуль должен быть отражён в дереве
зависимостей.
"outputs": {
"dist/app.js": {
"inputs": {
"src/index.js": {},
"src/missing.js": {}
}
}
}
Если ожидаемый файл отсутствует в inputs, это указывает
на:
externalПоле bytes на уровне inputs и
outputs позволяет быстро выявить тяжёлые модули. Сравнение
метафайлов между сборками показывает, какие зависимости увеличили вклад
в итоговый размер.
Пример анализа:
react-dom.production.min.js — 120 KBlodash — 500 KBchart.js — 250 KBТакое разбиение помогает локализовать источник роста без инструментов пост-анализа.
Metafile показывает, какие экспорты были фактически включены в бандл.
Если ожидается, что часть API должна быть исключена, но она присутствует
в outputs.imports, значит tree shaking не сработал.
Причины:
Структура inputs.imports формирует граф зависимостей,
который можно использовать для построения визуализации. Например, можно
программно преобразовать metafile в граф:
import fs from 'fs';
const metafile = JSON.parse(fs.readFileSync('meta.json', 'utf8'));
for (const [file, data] of Object.entries(metafile.inputs)) {
console.log(file, '->', data.imports?.map(i => i.path));
}
Это позволяет выявить:
В outputs.imports фиксируются зависимости, которые не
были встроены в бандл (например, помеченные как external).
Это критично для серверных сборок и библиотек.
"imports": [
"react",
"react-dom"
]
Такая информация используется для:
Один из наиболее практичных сценариев — сравнение двух metafile для оценки влияния изменений конфигурации.
Подход:
outputs.bytes и структуру
inputsДаже простая дифф-операция позволяет выявить:
Metafile легко преобразуется в формат, пригодный для визуализации графа зависимостей. Многие инструменты анализа бандлов используют именно его как входной формат.
Пример подготовки данных:
const graph = {};
for (const [file, data] of Object.entries(metafile.inputs)) {
graph[file] = data.imports?.map(i => i.path) || [];
}
Дальнейшая обработка может включать:
Metafile фиксирует результат работы плагинов косвенно через изменения
в графе зависимостей. Если плагин подменяет модуль, это отражается в
inputs.
Типичные сценарии анализа:
Если после подключения плагина появляются неожиданные узлы в
inputs, это сигнал о вмешательстве в резолвинг.
Metafile может быть включён в pipeline сборки для автоматического контроля регрессий.
Типичные метрики:
outputs.bytes)Object.keys(inputs).length)Эти показатели позволяют отслеживать:
Частая ошибка — воспринимать metafile как прямое отображение runtime-структуры приложения. На практике он отражает только статическую модель сборки.
Ограничения:
Также важно учитывать, что bytes отражает размер
исходного кода до минификации, если она не включена в конфигурацию.
В монорепозиториях metafile становится особенно полезным. Он позволяет:
При большом количестве модулей JSON может становиться объёмным, поэтому часто применяется постобработка:
Metafile легко интегрируется в скрипты анализа. Пример вычисления самых «тяжёлых» модулей:
const entries = Object.entries(metafile.inputs)
.map(([name, data]) => ({ name, bytes: data.bytes }))
.sort((a, b) => b.bytes - a.bytes);
console.log(entries.slice(0, 10));
Такой подход позволяет быстро находить узкие места без специализированных инструментов.
Metafile часто используется для проверки архитектурных ограничений:
Поскольку он отражает полный граф зависимостей, его можно использовать как основу для статического анализа архитектуры проекта.