Опция sourcesContent: включение исходников в карту

При сборке современных 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.

JavaScript API

await esbuild.build({
    entryPoints: ['src/index.js'],
    bundle: true,
    sourcemap: true,
    sourcesContent: false,
    outfile: 'dist/app.js'
});

CLI

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, он выполняет следующую последовательность действий:

  1. Загружает карту.
  2. Читает список файлов из sources.
  3. Проверяет наличие sourcesContent.
  4. Если поле существует — использует встроенные исходники.
  5. Если поле отсутствует — пытается загрузить файлы по указанным путям.

Схематично процесс выглядит так:

Source Map
      │
      ▼
Есть sourcesContent?
      │
 ┌────┴────┐
 │         │
Да         Нет
 │         │
 ▼         ▼
Использовать  Искать
встроенный    файл
код           по пути

Поэтому отключение параметра требует корректной публикации оригинальных исходников либо настройки путей доступа к ним.


Использование в production-сборках

В производственной среде наличие встроенных исходников часто считается нежелательным.

Причины:

Раскрытие внутреннего кода

Даже если приложение минифицировано:

(()=>{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'
});

Использование в development-сборках

Во время разработки ситуация обратная.

Встроенные исходники обеспечивают:

  • максимально удобную отладку;
  • независимость от файловой структуры;
  • корректное отображение кода в DevTools;
  • упрощённую работу удалённых отладчиков.

Типичная конфигурация:

await esbuild.build({
    entryPoints: ['src/index.js'],
    bundle: true,
    sourcemap: true,
    sourcesContent: true,
    outfile: 'dist/app.js'
});

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


Особенности при работе с удалёнными системами мониторинга

Сервисы анализа ошибок, например:

  • Sentry
  • Rollbar
  • Bugsnag

часто получают source maps отдельно от приложения.

Если карта содержит sourcesContent, сервис может самостоятельно восстановить исходный код без дополнительных файлов.

Пример процесса:

Ошибка
   │
   ▼
Минифицированный стек
   │
   ▼
Source Map
   │
   ▼
sourcesContent
   │
   ▼
Оригинальный код

Это существенно упрощает расшифровку стеков вызовов.


Когда рекомендуется включать sourcesContent

Опция обычно полезна в следующих случаях:

Локальная разработка

sourcesContent: true

Обеспечивает максимально удобную отладку.

Тестовые стенды

sourcesContent: true

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

Внутренние корпоративные приложения

sourcesContent: true

Если вопрос раскрытия исходного кода не является критичным.

Интеграция с системами мониторинга

sourcesContent: true

Позволяет сервисам самостоятельно восстанавливать оригинальные файлы.


Когда рекомендуется отключать sourcesContent

Наиболее распространённые случаи:

Публичные production-приложения

sourcesContent: false

Минимизируется риск раскрытия кода.

Крупные проекты

sourcesContent: false

Снижается объём карт.

Ограничения по трафику

sourcesContent: false

Уменьшается размер публикуемых артефактов.

Строгие требования безопасности

sourcesContent: false

Исключается хранение исходников внутри карты.


Комбинация с различными режимами source map

Параметр работает совместно со всеми вариантами генерации карт.

External

await esbuild.build({
    sourcemap: true,
    sourcesContent: false
});

Создаётся отдельный файл:

app.js
app.js.map

без встроенных исходников.


Inline

await esbuild.build({
    sourcemap: 'inline',
    sourcesContent: true
});

Карта помещается прямо внутрь JavaScript-файла и одновременно содержит тексты оригинальных файлов.

Такой вариант особенно удобен для разработки, но может значительно увеличить размер бандла.


Both

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-файлах.