Зачем вам CLI утилиты на JavaScript?
Представьте: вы каждый день вручную переименовываете папки с отчётами, конвертируете JSON в CSV или ищете дубликаты файлов. А что, если написать небольшую программу, которая сделает это за секунду по команде в терминале? Именно для этого и нужны CLI утилиты на JavaScript.
В отличие от полноценных веб-приложений, CLI (Command Line Interface) — это лёгкие, быстрые и очень удобные инструменты. Они не требуют браузера, работают на любой платформе и легко встраиваются в скрипты CI/CD. На PythonLib мы часто обсуждаем автоматизацию, и сегодня я покажу, как создать свою первую CLI-утилиту на Node.js с нуля. Вы удивитесь, насколько это просто!
В этой статье мы пройдём полный путь: от настройки проекта до публикации готового пакета в npm. Вы получите не просто теорию, а рабочий код, который можно сразу адаптировать под свои задачи.
Что такое CLI утилита и почему JavaScript?
CLI утилита — это программа, которая запускается из командной строки. Вы пишете my-tool --input file.txt — и она выполняет нужное действие. JavaScript для этого идеален, потому что:
- Node.js установлен на каждом сервере и почти на каждом ПК разработчика.
- Огромное количество готовых модулей (npm) для работы с файлами, сетью, форматами данных.
- Простота написания: не нужно компилировать, достаточно одного файла.
- Кроссплатформенность: ваш инструмент будет работать на Windows, macOS и Linux.
Даже если вы новичок в Node.js, вы справитесь. Мы начнём с самого простого — скрипта, который выводит приветствие.
Шаг 1: Настройка проекта для CLI утилиты
Создайте папку для вашего проекта и инициализируйте npm:
mkdir my-first-cli
cd my-first-cli
npm init -y
Теперь откройте package.json. Это главный конфиг вашей будущей CLI утилиты на JavaScript. Добавьте в него поле "bin":
{
"name": "my-first-cli",
"version": "1.0.0",
"description": "Моя первая CLI утилита",
"bin": {
"greet": "./index.js"
},
"license": "MIT"
}
Поле "bin" — это магия. Оно говорит Node.js: «Когда пользователь введёт команду greet, запусти файл index.js». Обратите внимание: имя команды (greet) может быть любым.
Теперь создайте index.js с первой строкой — шебангом (shebang). Это обязательно для CLI:
#!/usr/bin/env node
console.log('Привет, мир! Я твоя первая CLI утилита!');
Шебанг #!/usr/bin/env node указывает системе, что скрипт нужно выполнять с помощью Node.js. Без него команда не сработает.
Шаг 2: Делаем утилиту исполняемой и тестируем
Чтобы запустить вашу CLI утилиту на JavaScript локально, выполните команду:
npm link
Эта команда создаёт глобальную ссылку на ваш пакет. Теперь в любом терминале можно написать:
greet
И вы увидите: Привет, мир! Я твоя первая CLI утилита! Поздравляю, вы только что создали свою первую утилиту!
Шаг 3: Парсинг аргументов командной строки
Просто выводить текст — скучно. Настоящие CLI утилиты принимают аргументы. Давайте научимся их обрабатывать. В Node.js есть встроенный массив process.argv, но для серьёзных проектов лучше использовать модуль commander или yargs.
Установим commander:
npm install commander
Теперь перепишем index.js:
#!/usr/bin/env node
const { Command } = require('commander');
const program = new Command();
program
.name('greet')
.description('Утилита для приветствия')
.version('1.0.0');
program
.command('hello')
.description('Сказать привет')
.argument('<name>', 'Имя пользователя')
.option('-l, --language <lang>', 'Язык приветствия', 'ru')
.action((name, options) => {
if (options.language === 'en') {
console.log(`Hello, ${name}!`);
} else {
console.log(`Привет, ${name}!`);
}
});
program.parse(process.argv);
Теперь попробуйте:
greet hello Алексей
greet hello John --language en
Вывод будет разным. commander сам парсит аргументы, флаги и даже генерирует справку по команде --help.
Шаг 4: Работа с файлами — реальная польза
Давайте сделаем действительно полезную CLI утилиту на JavaScript: конвертер JSON в CSV. Это классика для автоматизации.
Создайте файл convert.js и добавьте новый код:
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const { Command } = require('commander');
const program = new Command();
program
.name('json2csv')
.description('Конвертирует JSON в CSV')
.version('1.0.0');
program
.command('convert')
.description('Конвертировать файл')
.argument('<input>', 'Путь к JSON файлу')
.option('-o, --output <file>', 'Имя выходного CSV файла', 'output.csv')
.action((input, options) => {
const inputPath = path.resolve(input);
if (!fs.existsSync(inputPath)) {
console.error('Ошибка: файл не найден');
process.exit(1);
}
const rawData = fs.readFileSync(inputPath, 'utf-8');
let jsonData;
try {
jsonData = JSON.parse(rawData);
} catch (e) {
console.error('Ошибка: неверный JSON');
process.exit(1);
}
if (!Array.isArray(jsonData) || jsonData.length === 0) {
console.error('Ошибка: JSON должен быть массивом объектов');
process.exit(1);
}
const headers = Object.keys(jsonData[0]);
const csvRows = jsonData.map(row =>
headers.map(header => JSON.stringify(row[header] ?? '')).join(',')
);
const csvContent = [headers.join(','), ...csvRows].join('\n');
const outputPath = path.resolve(options.output);
fs.writeFileSync(outputPath, csvContent, 'utf-8');
console.log(`Готово! CSV сохранён в ${output