При сборке современных JavaScript-приложений инструменты компиляции и бандлинга часто преобразуют исходный код: объединяют файлы, транспилируют новые возможности языка, удаляют неиспользуемые части и выполняют множество других операций. После таких преобразований структура итогового кода существенно отличается от оригинала. Для восстановления связи между результатом сборки и исходными файлами используются карты исходного кода (source maps).
Опция sourcesContent управляет тем, будут ли тексты
исходных файлов встроены непосредственно в карту исходного кода.
sourcesContentСтандартная карта исходного кода содержит несколько ключевых полей:
{
"version": 3,
"sources": [
"src/index.js",
"src/utils.js"
],
"names": [],
"mappings": "...",
"sourcesContent": [
"console.log('Hello');",
"export function sum(a, b) { return a + b; }"
]
}
Поле sources хранит пути к оригинальным файлам, а
sourcesContent — полный текст этих файлов.
Если содержимое присутствует внутри карты, инструменты отладки могут восстанавливать исходники даже при отсутствии доступа к оригинальным файлам на диске или сервере.
В Esbuild данное поведение настраивается через параметр
sourcesContent.
Во многих сценариях Esbuild автоматически включает исходный код в source map.
Пример:
await esbuild.build({
entryPoints: ['src/index.js'],
bundle: true,
sourcemap: true,
outfile: 'dist/app.js'
});
Сгенерированная карта может содержать секцию:
{
"sourcesContent": [
"...содержимое файла..."
]
}
Браузер или IDE смогут показывать оригинальный код непосредственно из карты.
sourcesContentДля исключения исходников из карты используется значение
false.
await esbuild.build({
entryPoints: ['src/index.js'],
bundle: true,
sourcemap: true,
sourcesContent: false,
outfile: 'dist/app.js'
});
esbuild src/index.js \
--bundle \
--sourcemap \
--sources-content=false \
--outfile=dist/app.js
После этого поле либо полностью исчезнет, либо будет пустым в зависимости от типа карты и версии инструмента.
Карта становится компактнее:
{
"version": 3,
"sources": [
"../src/index.js"
],
"names": [],
"mappings": "AAAA..."
}
В ней сохраняются ссылки на файлы и информация о соответствии строк и столбцов, но сами тексты файлов отсутствуют.
Для полноценной отладки инструменты должны иметь доступ к исходникам по указанным путям.
Одно из главных преимуществ отключения sourcesContent —
значительное уменьшение размера source map.
Рассмотрим проект:
src/
├─ app.js
├─ router.js
├─ store.js
├─ api.js
└─ helpers.js
Если общий объём исходного кода составляет:
450 КБ
то карта может содержать дополнительно те же самые 450 КБ текстовых данных.
Примерное сравнение:
| Конфигурация | Размер карты |
|---|---|
С sourcesContent |
620 КБ |
Без sourcesContent |
170 КБ |
Точные значения зависят от структуры проекта, однако разница зачастую оказывается весьма заметной.
Когда браузер получает source map, он выполняет следующую последовательность действий:
sources.sourcesContent.Схематично процесс выглядит так:
Source Map
│
▼
Есть sourcesContent?
│
┌────┴────┐
│ │
Да Нет
│ │
▼ ▼
Использовать Искать
встроенный файл
код по пути
Поэтому отключение параметра требует корректной публикации оригинальных исходников либо настройки путей доступа к ним.
В производственной среде наличие встроенных исходников часто считается нежелательным.
Причины:
Даже если приложение минифицировано:
(()=>{const a=5;console.log(a)})();
при наличии sourcesContent пользователь может увидеть
исходный вариант:
const value = 5;
console.log(value);
Фактически карта превращается в контейнер с оригинальными файлами.
Большие source map-файлы:
Некоторые организации запрещают публикацию исходного кода даже внутри карт исходников.
В подобных случаях используется конфигурация:
await esbuild.build({
bundle: true,
minify: true,
sourcemap: true,
sourcesContent: false,
outfile: 'dist/app.js'
});
Во время разработки ситуация обратная.
Встроенные исходники обеспечивают:
Типичная конфигурация:
await esbuild.build({
entryPoints: ['src/index.js'],
bundle: true,
sourcemap: true,
sourcesContent: true,
outfile: 'dist/app.js'
});
В результате браузер всегда располагает оригинальным кодом независимо от местоположения файлов.
Сервисы анализа ошибок, например:
часто получают source maps отдельно от приложения.
Если карта содержит sourcesContent, сервис может
самостоятельно восстановить исходный код без дополнительных файлов.
Пример процесса:
Ошибка
│
▼
Минифицированный стек
│
▼
Source Map
│
▼
sourcesContent
│
▼
Оригинальный код
Это существенно упрощает расшифровку стеков вызовов.
sourcesContentОпция обычно полезна в следующих случаях:
sourcesContent: true
Обеспечивает максимально удобную отладку.
sourcesContent: true
Позволяет быстро анализировать ошибки без доступа к исходному репозиторию.
sourcesContent: true
Если вопрос раскрытия исходного кода не является критичным.
sourcesContent: true
Позволяет сервисам самостоятельно восстанавливать оригинальные файлы.
sourcesContentНаиболее распространённые случаи:
sourcesContent: false
Минимизируется риск раскрытия кода.
sourcesContent: false
Снижается объём карт.
sourcesContent: false
Уменьшается размер публикуемых артефактов.
sourcesContent: false
Исключается хранение исходников внутри карты.
Параметр работает совместно со всеми вариантами генерации карт.
await esbuild.build({
sourcemap: true,
sourcesContent: false
});
Создаётся отдельный файл:
app.js
app.js.map
без встроенных исходников.
await esbuild.build({
sourcemap: 'inline',
sourcesContent: true
});
Карта помещается прямо внутрь JavaScript-файла и одновременно содержит тексты оригинальных файлов.
Такой вариант особенно удобен для разработки, но может значительно увеличить размер бандла.
await esbuild.build({
sourcemap: 'both',
sourcesContent: true
});
Создаются:
app.js
app.js.map
а также встроенная карта внутри результирующего файла.
Исходный код:
export function multiply(a, b) {
return a * b;
}
Сборка:
await esbuild.build({
entryPoints: ['src/math.js'],
bundle: true,
sourcemap: true,
sourcesContent: true,
outfile: 'dist/math.js'
});
Фрагмент карты:
{
"sources": [
"../src/math.js"
],
"sourcesContent": [
"export function multiply(a, b) {\n return a * b;\n}"
]
}
После изменения настройки:
await esbuild.build({
entryPoints: ['src/math.js'],
bundle: true,
sourcemap: true,
sourcesContent: false,
outfile: 'dist/math.js'
});
поле исчезает:
{
"sources": [
"../src/math.js"
],
"names": [],
"mappings": "AAAA..."
}
sourceRootПри отсутствии встроенных исходников особенно важным становится корректное указание путей.
Пример:
await esbuild.build({
sourcemap: true,
sourcesContent: false,
sourceRoot: '/src'
});
Тогда инструменты отладки будут искать файлы относительно указанного корневого каталога.
Если путь настроен неверно, DevTools сможет показать структуру файлов, но не сможет открыть содержимое.
Для локальной разработки:
{
sourcemap: true,
sourcesContent: true
}
Для тестовых окружений:
{
sourcemap: true,
sourcesContent: true
}
Для публичного production:
{
sourcemap: true,
sourcesContent: false
}
Для публикации карт в систему мониторинга:
{
sourcemap: true,
sourcesContent: true
}
Для крупных проектов с большими объёмами кода:
{
sourcemap: true,
sourcesContent: false
}
Опция sourcesContent является одним из ключевых
механизмов управления содержимым карт исходного кода в Esbuild. Она
позволяет выбирать между максимальным удобством отладки и минимальным
размером артефактов сборки, а также контролировать степень раскрытия
исходного кода в опубликованных source map-файлах.