Создание CLI-приложений на Node.js: фреймворки Commander и Yargs

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

CLI фреймворки для JavaScript (Node.js): Создание мощных консольных приложений

Разработка интерфейсов командной строки (CLI) — одна из ключевых задач в экосистеме Node.js. От простых скриптов до сложных инструментов для DevOps — CLI-приложения окружают нас повсюду. Однако написание парсера аргументов, обработка подкоманд и вывод справки вручную — утомительная и подверженная ошибкам работа. Именно здесь на помощь приходят CLI фреймворки для JavaScript (Node.js), которые берут на себя всю рутину.

В этой статье мы подробно разберём два самых популярных фреймворка: Commander.js и Yargs. Вы узнаете, как быстро создавать профессиональные CLI-приложения с поддержкой аргументов, опций, цветного вывода и автоматической генерации справки.

Commander.js — классика и простота

Commander.js — самый известный и широко используемый фреймворк для создания CLI на Node.js. Он используется в таких проектах, как Vue CLI, Angular CLI и многие другие. Его главное преимущество — интуитивно понятный API, основанный на цепочках вызовов.

Установка

npm install commander

Базовый пример

const { Command } = require('commander');
const program = new Command();

program
  .name('greet')
  .description('CLI для приветствия')
  .version('1.0.0');

program
  .command('hello')
  .description('Поприветствовать пользователя')
  .argument('<name>', 'Имя пользователя')
  .option('-l, --language <lang>', 'Язык приветствия', 'русский')
  .action((name, options) => {
    if (options.language === 'английский') {
      console.log(`Hello, ${name}!`);
    } else {
      console.log(`Привет, ${name}!`);
    }
  });

program.parse(process.argv);

В этом примере мы создали команду greet hello, которая принимает обязательный аргумент name и опциональную опцию --language. Commander автоматически сгенерирует справку по команде --help.

Поддержка подкоманд

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

const project = program.command('project');

project
  .command('init')
  .description('Инициализировать проект')
  .action(() => {
    console.log('Проект инициализирован');
  });

project
  .command('build')
  .description('Собрать проект')
  .option('-p, --production', 'Продакшн сборка')
  .action((options) => {
    console.log(options.production ? 'Продакшн сборка' : 'Обычная сборка');
  });

Yargs — гибкость и мощь

Yargs — ещё один мощный фреймворк, который фокусируется на парсинге аргументов и предоставляет очень гибкие возможности. Он особенно хорош, когда вам нужен точный контроль над поведением парсера, или когда вы строите сложные многоуровневые интерфейсы.

Установка

npm install yargs

Пример с Yargs

const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');

const argv = yargs(hideBin(process.argv))
  .command('serve [port]', 'Запустить сервер', (yargs) => {
    yargs
      .positional('port', {
        describe: 'Порт для сервера',
        default: 3000
      });
  }, (argv) => {
    console.log(`Сервер запущен на порту ${argv.port}`);
  })
  .option('verbose', {
    alias: 'v',
    type: 'boolean',
    description: 'Подробный вывод'
  })
  .example('$0 serve 8080', 'Запустить сервер на порту 8080')
  .demandCommand(1, 'Необходимо указать команду')
  .help()
  .argv;

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

Валидация и типы

Одно из сильных мест Yargs — встроенная валидация и контроль типов:

const argv = yargs(hideBin(process.argv))
  .option('count', {
    type: 'number',
    description: 'Количество элементов',
    demandOption: true
  })
  .option('name', {
    type: 'string',
    description: 'Имя пользователя'
  })
  .check((argv, options) => {
    if (argv.count < 0) {
      throw new Error('Количество не может быть отрицательным');
    }
    return true;
  })
  .argv;

Сравнение Commander.js

Рекомендаций