В среде Node.js входные аргументы командной строки доступны через
массив process.argv. Его структура фиксирована:
process.argv[0] — путь к интерпретатору Node.jsprocess.argv[1] — путь к выполняемому файлу
скриптаprocess.argv[2] — пользовательские
аргументыПри интеграции с esbuild этот механизм используется для построения собственных CLI-обёрток над сборкой, генерации конфигураций и динамического управления параметрами бандлинга.
console.log(process.argv);
При запуске:
node build.js src/index.js --minify --outdir=dist
структура массива будет включать как позиционные, так и флаговые значения.
В задачах сборки esbuild важно различать два типа аргументов:
--minify, --watch,
--outdir)Базовая схема разбиения:
const rawArgs = process.argv.slice(2);
const positional = [];
const flags = {};
for (const arg of rawArgs) {
if (arg.startsWith('--')) {
const [key, value] = arg.replace('--', '').split('=');
flags[key] = value ?? true;
} else {
positional.push(arg);
}
}
Такой подход позволяет подготовить данные для передачи в API esbuild.
Библиотека esbuild принимает конфигурацию в виде объекта:
import esbuild from 'esbuild';
Преобразование аргументов CLI в конфигурацию:
const config = {
entryPoints: positional.length ? positional : ['src/index.js'],
bundle: true,
platform: flags.platform || 'browser',
minify: Boolean(flags.minify),
sourcemap: flags.sourcemap === 'true' || flags.sourcemap === true,
outdir: flags.outdir || 'dist'
};
Так формируется слой адаптации между CLI и API.
CLI-аргументы часто не содержат значений. Например:
--minify
--watch
В таких случаях значение интерпретируется как true.
function toBoolean(value) {
if (value === undefined) return true;
if (value === 'true') return true;
if (value === 'false') return false;
return Boolean(value);
}
Использование:
minify: toBoolean(flags.minify)
Некоторые параметры esbuild требуют числовых значений, например
logLevel, chunkNames (в сторонних обёртках),
лимиты и кастомные настройки.
Преобразование:
function toNumber(value, fallback = 0) {
const n = Number(value);
return Number.isNaN(n) ? fallback : n;
}
Пример:
logLevel: toNumber(flags.logLevel, 2)
Параметры CLI могут содержать списки через разделители:
--external:react,react-dom
Разбор:
function toList(value) {
if (!value) return [];
return value.split(',').map(s => s.trim()).filter(Boolean);
}
Использование в esbuild:
external: toList(flags.external)
CLI часто допускает несовместимые комбинации:
--watch и --minify--outfile и --outdir--bundle и одиночная компиляция без входной точкиЛогика проверки:
function validate(config) {
if (config.outfile && config.outdir) {
throw new Error('Нельзя использовать outfile и outdir одновременно');
}
if (config.watch && config.minify) {
throw new Error('watch несовместим с minify в данном режиме');
}
}
Структура приоритетов обычно следующая:
build.config.js)Слияние:
const finalConfig = {
...defaultConfig,
...fileConfig,
...configFromCLI
};
Для вложенных объектов используется глубокое слияние:
function deepMerge(a, b) {
const result = { ...a };
for (const key in b) {
if (typeof b[key] === 'object' && !Array.isArray(b[key])) {
result[key] = deepMerge(a[key] || {}, b[key]);
} else {
result[key] = b[key];
}
}
return result;
}
CLI-параметры часто комбинируются с process.env:
const config = {
minify: toBoolean(flags.minify ?? process.env.MINIFY),
sourcemap: toBoolean(flags.sourcemap ?? process.env.SOURCEMAP)
};
Приоритет обычно ниже CLI, но выше дефолтов.
Режим watch в esbuild требует отдельной логики
запуска:
if (config.watch) {
const ctx = await esbuild.context(config);
await ctx.watch();
} else {
await esbuild.build(config);
}
CLI-аргумент:
--watch
Флаг переключает поведение с однократной сборки на постоянное отслеживание файлов.
Позиционные аргументы часто интерпретируются как entry points:
config.entryPoints = positional.length
? positional
: ['src/index.js'];
Поддержка нескольких входов:
node build.js src/a.js src/b.js
Для удобства CLI часто поддерживает короткие формы:
-w → --watch-m → --minify-o → --outdirПарсинг:
const aliasMap = {
w: 'watch',
m: 'minify',
o: 'outdir'
};
function expandFlags(args) {
const result = [];
for (const arg of args) {
if (arg.startsWith('-') && !arg.startsWith('--')) {
const chars = arg.slice(1).split('');
for (const c of chars) {
result.push(`--${aliasMap[c] || c}`);
}
} else {
result.push(arg);
}
}
return result;
}
Неверные аргументы должны выявляться до запуска esbuild:
function assertValidFlags(flags) {
const allowed = [
'minify',
'watch',
'outdir',
'outfile',
'platform',
'sourcemap'
];
for (const key of Object.keys(flags)) {
if (!allowed.includes(key)) {
throw new Error(`Неизвестный флаг: ${key}`);
}
}
}
Финальный этап — передача сформированной конфигурации:
import esbuild from 'esbuild';
async function run() {
const rawArgs = process.argv.slice(2);
const expanded = expandFlags(rawArgs);
const { positional, flags } = parse(expanded);
const config = buildConfig(positional, flags);
validate(config);
await esbuild.build(config);
}
run();
Чистая архитектура обработки CLI обычно разделяется на слои:
process.argv)Такое разделение позволяет масштабировать CLI без привязки к API esbuild.
Некоторые значения CLI могут содержать специальные символы:
--define:process.env.NODE_ENV='"production"'
Обработка требует сохранения экранирования:
function stripQuotes(value) {
return value.replace(/^['"]|['"]$/g, '');
}
Типичный цикл:
process.argvesbuild.build или
esbuild.contextПри усложнении сборочных сценариев добавляются:
--profile=dev|prod)CLI-слой остаётся точкой входа, изолирующей esbuild от внешних источников данных.