Опция dropLabels

Опция dropLabels в Esbuild предназначена для удаления помеченных операторов (labeled statements) из итогового кода во время сборки. Она позволяет исключать определённые блоки кода без использования условной компиляции, переменных окружения или дополнительных инструментов трансформации.

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

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


Что такое метки в JavaScript

JavaScript поддерживает специальные конструкции — метки (labels).

Простейший пример:

debug: {
    console.log("Отладка");
}

Здесь debug является меткой для блока кода.

Также метки могут использоваться с циклами:

outerLoop:
for (let i = 0; i < 10; i++) {
    for (let j = 0; j < 10; j++) {
        if (j === 5) {
            break outerLoop;
        }
    }
}

В обычном JavaScript метки применяются редко, однако Esbuild использует их как удобный механизм маркировки кода для последующего удаления.


Базовый синтаксис

Конфигурация через JavaScript API:

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

Исходный код:

DEBUG: {
    console.log("Отладочная информация");
}

console.log("Основная логика");

Результат:

console.log("Основная логика");

Блок с меткой DEBUG полностью исчезнет из сборки.


Массив меток

Параметр принимает массив строк.

Пример:

await esbuild.build({
    dropLabels: [
        'DEBUG',
        'TEST',
        'DEV_ONLY'
    ]
});

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

Исходный код:

DEBUG: {
    console.log("debug");
}

TEST: {
    console.log("test");
}

DEV_ONLY: {
    console.log("dev");
}

console.log("production");

Результат:

console.log("production");

Использование через CLI

Передача опции через командную строку:

esbuild src/index.js \
  --bundle \
  --drop-labels=DEBUG \
  --outfile=dist/app.js

Несколько меток:

esbuild src/index.js \
  --bundle \
  --drop-labels=DEBUG,TEST,DEV_ONLY \
  --outfile=dist/app.js

Использование через Go API

Поскольку Esbuild написан на Go, соответствующая возможность присутствует и в Go API.

Конфигурация:

result := api.Build(api.BuildOptions{
    EntryPoints: []string{"src/index.js"},
    Bundle: true,
    DropLabels: []string{
        "DEBUG",
        "TEST",
    },
    Outfile: "dist/app.js",
})

Удаление отладочных сообщений

Один из наиболее распространённых сценариев использования.

Исходный код:

DEBUG: {
    console.log("User:", user);
    console.log("Config:", config);
    console.log("State:", state);
}

После сборки:

Весь блок удаляется.

В отличие от конструкции:

if (process.env.NODE_ENV !== 'production') {
    console.log(user);
}

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


Удаление сложной диагностической логики

Часто требуется временно добавить объёмный код для исследования ошибок.

Пример:

DEBUG: {
    const report = generateDebugReport();

    saveReport(report);

    sendDebugInfo(report);

    console.log(report);
}

После применения dropLabels данный код исчезнет полностью.

Преимущество заключается в том, что не остаётся даже следов вызовов функций или промежуточных переменных.


Использование для тестовых сценариев

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

Пример:

TEST: {
    runBenchmark();
    runMemoryTest();
    runStressTest();
}

Для production-сборки:

dropLabels: ['TEST']

Результат:

Тестовые процедуры не попадут в финальный пакет.


Несколько независимых категорий кода

Крупные проекты часто используют различные уровни служебной логики.

Пример:

DEBUG: {
    logDebugInfo();
}

TEST: {
    runTests();
}

ANALYTICS: {
    collectMetrics();
}

console.log("Application");

Можно удалять только определённые группы:

dropLabels: ['DEBUG', 'TEST']

Результат:

ANALYTICS: {
    collectMetrics();
}

console.log("Application");

Отличие от drop

В Esbuild существует ещё одна опция — drop.

Пример:

drop: ['console']

Она удаляет вызовы console.*.

Однако dropLabels работает принципиально иначе.

drop

Удаляет определённые конструкции:

console.log("test");

Результат:

dropLabels

Удаляет целые помеченные блоки:

DEBUG: {
    console.log("test");
    doSomething();
    calculate();
}

Результат:

То есть удаляется не конкретный вызов, а вся секция.


Отличие от Dead Code Elimination

Esbuild обладает механизмом удаления мёртвого кода (Dead Code Elimination).

Пример:

if (false) {
    console.log("test");
}

Такой код может быть удалён оптимизатором.

Однако для этого необходимо, чтобы условие было известно на этапе сборки.

С dropLabels ситуация проще:

DEBUG: {
    console.log("test");
}

Esbuild удаляет блок без анализа условий.


Отличие от условной компиляции через define

Многие проекты используют:

if (__DEV__) {
    console.log("debug");
}

Конфигурация:

define: {
    __DEV__: 'false'
}

После чего выполняется оптимизация.

Вариант с метками выглядит компактнее:

DEBUG: {
    console.log("debug");
}

И конфигурация:

dropLabels: ['DEBUG']

Особенно удобно при наличии больших диагностических блоков.


Удаление вложенных конструкций

Внутри метки может находиться любой код.

Пример:

DEBUG: {
    if (user) {
        for (const role of user.roles) {
            console.log(role);
        }
    }
}

После сборки:

Все вложенные операторы удаляются вместе с блоком.


Работа с функциями

Метка может содержать вызовы функций:

DEBUG: {
    initializeDebugTools();
}

После удаления:

Вызов функции не выполняется и не попадает в выходной файл.


Работа с асинхронным кодом

Пример:

DEBUG: {
    await fetch('/debug');
}

После применения dropLabels:

Асинхронная операция полностью исчезает из результата сборки.


Работа внутри модулей

Исходный модуль:

import { logger } from './logger.js';

DEBUG: {
    logger.printAll();
}

export function start() {
    console.log("started");
}

После удаления метки:

export function start() {
    console.log("started");
}

Если импорт больше нигде не используется, Esbuild дополнительно может удалить его благодаря tree shaking.


Влияние на размер бандла

Одна из основных причин использования dropLabels — уменьшение размера итогового пакета.

Пример:

DEBUG: {
    hugeDiagnosticFunction();
    logEntireApplicationState();
    generateDebugDump();
}

Удаление таких блоков позволяет:

  • уменьшить размер JavaScript-файлов;
  • сократить время парсинга браузером;
  • уменьшить объём передаваемых данных;
  • исключить лишние зависимости.

Практика именования меток

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

DEBUG:
DEV:
TEST:
INTERNAL:
BENCHMARK:
PROFILING:
EXPERIMENTAL:

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


Ограничения

Удаляются только указанные метки

Если конфигурация содержит:

dropLabels: ['DEBUG']

код:

TEST: {
    runTests();
}

останется без изменений.


Метка должна совпадать полностью

Конфигурация:

dropLabels: ['DEBUG']

Код:

DEBUG_MODE: {
    console.log("test");
}

не будет удалён.

Сравнение выполняется по точному имени.


Метки чувствительны к регистру

Пример:

dropLabels: ['DEBUG']

Код:

debug: {
    console.log("test");
}

останется в результате.

Корректное совпадение:

DEBUG: {
    console.log("test");
}

Рекомендации по использованию

Отделение отладочной логики

DEBUG: {
    printStoreState();
}

Такой подход делает код более читаемым, чем множество условных операторов.

Маркировка временных экспериментов

EXPERIMENTAL: {
    runPrototypeFeature();
}

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

Выделение нагрузочных тестов

BENCHMARK: {
    benchmarkParser();
}

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

Использование единой системы меток

Например:

DEBUG
TEST
BENCHMARK
PROFILING
INTERNAL

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


Взаимодействие с другими оптимизациями Esbuild

dropLabels хорошо сочетается с:

  • minify;
  • tree shaking;
  • define;
  • drop;
  • bundle;
  • splitting.

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

await esbuild.build({
    entryPoints: ['src/index.js'],
    bundle: true,
    minify: true,
    treeShaking: true,
    drop: ['console'],
    dropLabels: [
        'DEBUG',
        'TEST',
        'PROFILING'
    ],
    outfile: 'dist/app.js'
});

В результате удаляются отладочные сообщения, тестовые блоки, профилировочные секции и неиспользуемый код, что позволяет получить максимально компактную производственную сборку.