Владислав Калачев

Пишем свой CLI

24

В какой-то момент своей карьеры frontend-разработчика я столкнулся с ситуацией, когда рутинные задачи начали занимать слишком много времени. Эти задачи были однотипными, повторяющимися, и, честно говоря, скучными. Постоянная настройка окружения, сборка проекта, обновление зависимостей, запуск тестов – всё это требовало ручного вмешательства каждый раз. Тогда я подумал: «Почему бы не автоматизировать это через свою собственную CLI (Command Line Interface)?»

Зачем вообще нужна своя CLI?

На первый взгляд, кажется, что разработка собственной CLI — это излишество, особенно когда существуют готовые инструменты, такие как npm, yarn, webpack и множество других. Однако, сталкиваясь с проектами, которые требуют специфической настройки или выполнения уникальных команд, я пришёл к выводу, что стандартные инструменты не всегда дают достаточную гибкость. Некоторые команды требовали множественных шагов, которых можно было избежать. К тому же, CLI-интерфейс позволил бы мне улучшить продуктивность команды, минимизировав количество ошибок при выполнении рутинных задач.

Проблема на работе

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

Путь к решению: создание собственной CLI

Я решил, что пора решить эту проблему раз и навсегда, и занялся созданием своей CLI, которая бы автоматизировала большую часть рутинных процессов. В процессе работы над инструментом я прошёл через несколько ключевых шагов:

1. Определение функциональности

Первым делом я решил, какие именно задачи должна решать моя CLI. Основные требования были следующие:

Автоматическое переключение веток и пересборка проекта;

Проверка и обновление зависимостей;

Запуск тестов и деплой;

Создание конфигураций для разных окружений (staging, production).

2. Выбор инструментов

Я выбрал Node.js и пакет Commander.js для создания интерфейса командной строки. Этот инструмент оказался достаточно гибким и позволил легко добавлять команды и опции. Альтернативой мог быть yargs, но Commander.js показался мне более удобным для нужд проекта.


const { exec } = require('child_process');
const { program } = require('commander');

program
  .command('switch-branch ')
  .description('Переключение на указанную ветку и пересборка проекта')
  .action((branch) => {
    exec(`git checkout ${branch}`, (error, stdout, stderr) => {
      if (error) {
        console.error(`Ошибка переключения ветки: ${error.message}`);
        return;
      }
      console.log(`Переключено на ветку: ${branch}`);
      console.log('Запуск пересборки...');
      exec('npm run build', (buildError) => {
        if (buildError) {
          console.error(`Ошибка сборки: ${buildError.message}`);
          return;
        }
        console.log('Проект успешно собран.');
      });
    });
  });

program.parse(process.argv);

3. Реализация автоматизации

Создание своей CLI требует чёткого понимания того, какие задачи мы хотим автоматизировать и как они будут выполняться. В моём случае основная задача заключалась в том, чтобы автоматизировать процесс переключения веток в Git и пересборки проекта. Этот процесс в нашем проекте выглядел следующим образом:

1. Разработчик выбирал нужную ветку в Git.

2. Выполнял команду git checkout <branch> для переключения на неё.

3. Затем запускал сборку проекта через npm run build.

4. Если проект был сложным, каждый раз приходилось проверять, установлены ли все зависимости, и при необходимости обновлять их с помощью npm install.

Каждый раз проходить все эти шаги вручную было неудобно и занимало время. Решение состояло в том, чтобы объединить эти шаги в одну CLI-команду.

Структура команды

Команда в CLI должна:

Принимать название ветки, на которую нужно переключиться;

Проверить, нет ли ошибок при переключении;

Запускать сборку проекта после успешного переключения;

Обрабатывать возможные ошибки, чтобы разработчик сразу видел, что пошло не так.

Детальный разбор кода

Давайте разберём код по частям и добавим больше деталей.


const { exec } = require('child_process');
const { program } = require('commander');

Для выполнения команд в терминале используется встроенный модуль Node.js child_process. Метод exec позволяет запускать команды в командной строке прямо из нашего скрипта. Пакет commander помогает организовать интерфейс командной строки и позволяет легко добавлять команды с описанием и параметрами.

Переключение ветки

Начнём с команды для переключения ветки:


program
  .command('switch-branch ') // Команда принимает аргумент branch
  .description('Переключение на указанную ветку и пересборка проекта') // Описание команды
  .action((branch) => {
    exec(`git checkout ${branch}`, (error, stdout, stderr) => { // Запуск команды git checkout
      if (error) {
        console.error(`Ошибка переключения ветки: ${error.message}`); // Обработка ошибки
        return;
      }
      console.log(`Переключено на ветку: ${branch}`); // Вывод успеха в консоль

На этом этапе программа:

1. Принимает название ветки от пользователя.

2. Вызывает команду git checkout <branch> для переключения на нужную ветку.

3. Проверяет, успешно ли произошло переключение. Если произошла ошибка (например, ветка не существует или имеются несохранённые изменения), она выводит сообщение об ошибке и останавливается.

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

Пересборка проекта

Следующий шаг — автоматическая сборка проекта после переключения ветки:


     console.log('Запуск пересборки...');
      exec('npm run build', (buildError, stdout, stderr) => { // Запуск сборки проекта
        if (buildError) {
          console.error(`Ошибка сборки: ${buildError.message}`); // Обработка ошибки сборки
          return;
        }
        console.log('Проект успешно собран.');
      });
    });
  });

После успешного переключения ветки программа:

1. Выводит сообщение о том, что начинается пересборка.

2. Запускает команду npm run build, которая выполняет сборку проекта.

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

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

Проверка зависимостей (дополнительно)

Один из наиболее частых источников ошибок во время сборки — это несовместимые или отсутствующие зависимости. Поэтому я добавил возможность автоматической проверки зависимостей перед сборкой:


  exec('npm install', (installError) => {
  if (installError) {
    console.error(`Ошибка установки зависимостей: ${installError.message}`);
    return;
  }
  console.log('Все зависимости успешно установлены.');
  exec('npm run build', (buildError) => {
    if (buildError) {
      console.error(`Ошибка сборки: ${buildError.message}`);
      return;
    }
    console.log('Проект успешно собран.');
  });
});

Теперь команда:

1. Выполняет npm install, чтобы убедиться, что все зависимости установлены и обновлены.

2. Если установка зависимостей прошла успешно, запускает сборку проекта.

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

4. Тестирование и доработка

После того как базовые команды были реализованы, я протестировал CLI на нескольких проектах. Конечно, по ходу тестирования возникли ошибки и недочёты, которые пришлось оперативно устранять. Например, иногда сборка зависала из-за конфликтов в зависимостях, и мне пришлось реализовать обработку таких ситуаций.

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

Заключение

Создание собственной CLI-интерфейса — это отличный способ не только автоматизировать повторяющиеся задачи, но и повысить продуктивность команды. Да, на разработку такого инструмента ушло некоторое время, но итоговый результат стоил того. Теперь наша команда может быстрее сосредотачиваться на важнейших задачах, а не тратить время на рутину.

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

Комментарии:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *