- Оригинальный адрес:How to build a CLI with Node.js
- Оригинальный автор:dkundel
- Перевод с:Программа перевода самородков
- Постоянная ссылка на эту статью:GitHub.com/rare earth/gold-no…
- Переводчик:EmilyQiRabbit
- Корректор:suhanyujie
Встроенное в Node.js приложение командной строки (CLI) позволяет автоматизировать повторяющиеся задачи, используя его обширную экосистему. И, благодаря чему-то вродеnpm
иyarn
Такие инструменты управления пакетами позволяют легко распространять эти приложения командной строки и использовать их на нескольких платформах. В этой статье я опишу, почему вам нужно написать CLI, как это сделать с помощью Node.js, некоторые полезные пакеты и как вы можете опубликовать только что написанный CLI.
Зачем использовать Node.js для создания приложений командной строки
Одной из причин популярности Node.js является богатая экосистема пакетов, которая сейчасnpm
регистрУже более 900 000 пакетов. Написав свой собственный CLI на Node.js, вы сможете подключиться к этой экосистеме, которая также включает в себя огромное количество пакетов, специфичных для CLI. включают:
-
inquirer
,enquirer
илиprompts
, который можно использовать для обработки сложных запросов ввода. -
email-prompt
Ввод электронной почты можно легко запросить -
chalk
илиkleur
Доступен для цветной печати -
ora
хорошая подсказка о загрузке -
boxen
Может использоваться для добавления границ к вашему выводу -
stmux
может предоставить иtmux
Аналогичный многотерминальный интерфейс -
listr
Может отображать список процессов -
ink
CLI можно построить с помощью React -
meow
илиarg
Может использоваться для разбора основных параметров -
commander
иyargs
Может использоваться для более сложного анализа параметров и поддерживает подкоманды. -
oclif
это фреймворк для создания расширяемых интерфейсов командной строки от Heroku (gluegun
как альтернатива)
Также существует множество удобных способов использования CLI, все они опубликованы вnpm
, можно использовать одновременноyarn
иnpm
справляться. Напримерcreate-flex-plugin
, который можно использовать дляTwilio FlexCLI для создания плагинов. Вы можете установить его с помощью глобальной команды:
# 使用 npm 安装:
npm install -g create-flex-plugin
# 使用 yarn 安装:
yarn global add create-flex-plugin
# 安装之后你就可以使用了:
create-flex-plugin
Или его также можно использовать как зависимость проекта:
# 使用 npm 安装:
npm install create-flex-plugin --save-dev
# 使用 yarn 安装:
yarn add create-flex-plugin --dev
# 安装之后命令将被保存在
./node_modules/.bin/create-flex-plugin
# 或者通过由 npm 支持的 npx 使用:
npx create-flex-plugin
# 以及通过 yarn 使用:
yarn create-flex-plugin
По факту,npx
Может поддерживать выполнение CLI без установки. просто бегиnpx create-flex-plugin
, то, если он не сможет найти локальную или глобальную установленную версию, он автоматически загрузит пакет и поместит его в кеш.
отnpm
После версии 6.1,npm init
иyarn
Оба поддерживают использование CLI для сборки проекта, имя команды похоже наcreate-*
. Например, только что сказалcreate-flex-plugin
, все, что нам нужно сделать, это:
# 使用 Node.js:
npm init flex-plugin
# 使用 Yarn:
yarn create flex-plugin
Создайте свой первый интерфейс командной строки
Если вы предпочитаете смотреть обучающие видео,Нажмите здесь, чтобы посмотреть обучающее видео на YouTube.
Теперь, когда мы объяснили причины создания CLI с Node.js, давайте начнем создавать CLI. В этом уроке мы будем использоватьnpm
, но если вы хотите использоватьyarn
, подавляющее большинство команд также одинаковы. Убедитесь, что вы установили его в своей системеNode.jsиnpm
.
В этом руководстве мы создадим CLI, выполнив командуnpm init @your-username/project
, который может построить новый проект в соответствии с вашими предпочтениями.
Запустите новый проект Node.js, выполнив следующий код:
mkdir create-project && cd create-project
npm init --yes
Затем в корневом каталоге проекта создайте файл с именемsrc/
каталог, затем поместите файл с именемcli.js
файл в этом каталоге и напишите код в файле:
export function cli(args) {
console.log(args);
}
В этой функции мы будем анализировать логику параметров и запускать фактическую требуемую бизнес-логику. Далее нам нужно создать запись для CLI. Создайте каталог в корневом каталоге проектаbin/
Затем создайте файл с именемcreate-project
документ. написать код:
#!/usr/bin/env node
require = require('esm')(module /*, options*/);
require('../src/cli').cli(process.argv);
В этом небольшом фрагменте кода делается несколько вещей. Во-первых, мы вводимesm
модуль, который позволяет нам использовать его в других файлахimport
. Это не имеет прямого отношения к построению CLI, но для этого руководства нам нужно использоватьмодуль ЕС, в то время как пакетesm
Позволяет нам использовать ES-модули без транскодирования, когда версия Node.js его не поддерживает. Затем мы вводимcli.js
файл и вызвать функциюcli
, и воляprocess.argv
Pass in — массив аргументов, передаваемых в скрипт функции из командной строки.
Прежде чем мы сможем протестировать скрипт, его необходимо установить, выполнив следующую командуesm
полагаться:
npm install esm
Кроме того, нам необходимо синхронизировать требование предоставления CLI-скрипта диспетчеру пакетов. метод находится вpackage.json
Добавьте соответствующую запись в файл. Не забудьте также обновить свойстваdescription
,name
,keyword
иmain
:
{
"name": "@your_npm_username/create-project",
"version": "1.0.0",
"description": "A CLI to bootstrap my new projects",
"main": "src/index.js",
"bin": {
"@your_npm_username/create-project": "bin/create-project",
"create-project": "bin/create-project"
},
"publishConfig": {
"access": "public"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"cli",
"create-project"
],
"author": "YOUR_AUTHOR",
"license": "MIT",
"dependencies": {
"esm": "^3.2.18"
}
}
Если вы заметитеbin
свойство, вы заметите, что мы определяем его как объект с двумя парами ключ-значение. В этом объекте определены команды CLI, которые установит менеджер пакетов. В приведенном выше примере мы зарегистрировали две команды для одного и того же скрипта. Один использует свое, добавив наше имя пользователяnpm
сфера применения, другая является универсальной для простоты использованияcreate-project
Заказ.
После этого мы можем протестировать скрипт. Самый простой способ проверить это использоватьnpm link
Заказ. В терминале вашего проекта запустите:
npm link
Эта команда установит ссылку на ваш текущий проект глобально, поэтому вам не нужно повторно запускать ее при обновлении кода.npm link
Заказ. Бегnpm link
ваша команда CLI уже должна быть доступна. Попробуйте запустить:
create-project
Вы должны увидеть вывод, похожий на:
[ '/usr/local/Cellar/node/11.6.0/bin/node',
'/Users/dkundel/dev/create-project/bin/create-project' ]
Обратите внимание, что эти два адреса зависят от адреса вашего проекта и адреса установки Node.js и соответственно будут различаться. И этот массив становится длиннее по мере добавления параметров. Попробуйте запустить:
create-project --yes
Вывод теперь отражает добавление нового параметра:
[ '/usr/local/Cellar/node/11.6.0/bin/node',
'/Users/dkundel/dev/create-project/bin/create-project',
'--yes' ]
Разбор параметров и обработка ввода
Теперь мы готовы разобрать переданные в скрипт аргументы и придать им логическое значение. Наш CLI поддерживает один параметр и несколько опций:
-
[template]
: Мы поддерживаем мульти-шаблон из коробки. Если пользователь не проходит в этом параметре, мы дадим запрос для пользователя выбрать -
--git
: будет работатьgit init
, чтобы создать новый проект git -
--install
: он автоматически установит все зависимости для проекта -
--yes
: он пропустит все подсказки и просто использует параметры по умолчанию
Для нашего проекта мы будем использоватьinquirer
запросить параметры и использоватьarg
библиотека для анализа параметров CLI. Установите зависимости, выполнив следующую команду:
npm install inquirer arg
Для начала напишем логику парсинга параметров, процесс парсинга будет парсить параметры вoptions
объект, для нашего использования. Добавьте следующий код вcli.js
середина:
import arg from 'arg';
function parseArgumentsIntoOptions(rawArgs) {
const args = arg(
{
'--git': Boolean,
'--yes': Boolean,
'--install': Boolean,
'-g': '--git',
'-y': '--yes',
'-i': '--install',
},
{
argv: rawArgs.slice(2),
}
);
return {
skipPrompts: args['--yes'] || false,
git: args['--git'] || false,
template: args._[0],
runInstall: args['--install'] || false,
};
}
export function cli(args) {
let options = parseArgumentsIntoOptions(args);
console.log(options);
}
бегатьcreate-project --yes
, вы сможете увидетьskipPrompt
станетtrue
или попробуйте передать другие параметры, например.create-project cli
,Такtemplate
свойства будут установлены.
Теперь, когда мы можем анализировать параметры CLI, нам также нужно добавить методы, запрашивающие у пользователя информацию о параметрах, и когда--yes
Когда флаг введен, пропустите подсказку и используйте параметры по умолчанию. Добавьте следующий кодcli.js
документ:
import arg from 'arg';
import inquirer from 'inquirer';
function parseArgumentsIntoOptions(rawArgs) {
// ...
}
async function promptForMissingOptions(options) {
const defaultTemplate = 'JavaScript';
if (options.skipPrompts) {
return {
...options,
template: options.template || defaultTemplate,
};
}
const questions = [];
if (!options.template) {
questions.push({
type: 'list',
name: 'template',
message: 'Please choose which project template to use',
choices: ['JavaScript', 'TypeScript'],
default: defaultTemplate,
});
}
if (!options.git) {
questions.push({
type: 'confirm',
name: 'git',
message: 'Initialize a git repository?',
default: false,
});
}
const answers = await inquirer.prompt(questions);
return {
...options,
template: options.template || answers.template,
git: options.git || answers.git,
};
}
export async function cli(args) {
let options = parseArgumentsIntoOptions(args);
options = await promptForMissingOptions(options);
console.log(options);
}
сохраните файл и запуститеcreate-project
, вы увидите приглашение выбора шаблона, подобное этому:
После этого вас спросят, хотите ли вы инициализироватьgit
. После выбора обоих вопросов вы увидите вывод, подобный этому:
{ skipPrompts: false,
git: false,
template: 'JavaScript',
runInstall: false }
попробуй убежатьcreate-project -y
команда, все подсказки будут игнорироваться на этом этапе. Вы сразу увидите параметры, введенные в командной строке:
написать логику кода
Теперь, когда мы можем определить соответствующие логические параметры с помощью информации о приглашении и параметров командной строки, давайте напишем логический код, который может создать проект. Наш CLI будет работать сnpm init
Команда аналогична записи в существующий каталог и будетtemplates
Файлы в каталоге копируются в проект. Мы также разрешаем параметры для изменения адреса целевого каталога, поэтому вы можете повторно использовать эту логику в других проектах.
Прежде чем мы напишем логический код, создадим файл с именемtemplates
каталог и поместите каталогtypescript
иjavascript
размещены в этом каталоге. Все их имена — строчные версии, и мы предложим пользователю выбрать одно из них. В этой статье мы будем использовать эти два имени, но вы можете использовать любое другое имя. В этот каталог поместите файлpackage.json
И добавьте любые основные зависимости проекта, которые вам нужны, и любые файлы, которые вам нужно скопировать в проект. Затем наш код скопирует все эти файлы в новый проект. Если вам нужно творческое вдохновение, вы можете просмотреть файлы, которые я использовал, на github.com/dkundel/create-project.
Чтобы скопировать все файлы рекурсивно, мы будем использовать файл под названиемncp
библиотека. Эта библиотека поддерживает рекурсивное копирование между платформами и даже имеет флаги для принудительной перезаписи существующих файлов. Кроме того, чтобы иметь возможность отображать цветной вывод, мы также установимchalk
. Запустите следующий код для установки зависимостей:
npm install ncp chalk
Мы поместим основную логику проекта вsrc/
в каталогеmain.js
в файле. Создайте новый файл и добавьте следующий код:
import chalk from 'chalk';
import fs from 'fs';
import ncp from 'ncp';
import path from 'path';
import { promisify } from 'util';
const access = promisify(fs.access);
const copy = promisify(ncp);
async function copyTemplateFiles(options) {
return copy(options.templateDirectory, options.targetDirectory, {
clobber: false,
});
}
export async function createProject(options) {
options = {
...options,
targetDirectory: options.targetDirectory || process.cwd(),
};
const currentFileUrl = import.meta.url;
const templateDir = path.resolve(
new URL(currentFileUrl).pathname,
'../../templates',
options.template.toLowerCase()
);
options.templateDirectory = templateDir;
try {
await access(templateDir, fs.constants.R_OK);
} catch (err) {
console.error('%s Invalid template name', chalk.red.bold('ERROR'));
process.exit(1);
}
console.log('Copy project files');
await copyTemplateFiles(options);
console.log('%s Project ready', chalk.green.bold('DONE'));
return true;
}
Этот код экспортирует файл с именемcreateProject
Новая функция этой функции сначала проверит, доступен ли указанный шаблон.Метод проверки заключается в использованииfs.access
проверить читабельность файла (fs.constants.R_OK
), затем используйтеncp
Скопируйте файл в указанный каталог. Кроме того, после успешного копирования нам также необходимо вывести несколько цветных логов, содержимоеDONE Project ready
.
После этого обновитеcli.js
, добавив пару новых функцийcreateProject
Призыв к:
import arg from 'arg';
import inquirer from 'inquirer';
import { createProject } from './main';
function parseArgumentsIntoOptions(rawArgs) {
// ...
}
async function promptForMissingOptions(options) {
// ...
}
export async function cli(args) {
let options = parseArgumentsIntoOptions(args);
options = await promptForMissingOptions(options);
await createProject(options);
}
Чтобы проверить наш прогресс, где-то в вашей системе, например.~/test-dir
Создайте новый каталог в , и запустите команду внутри этой папки с шаблоном. Например:
create-project typescript --git
Вы должны увидеть уведомление о том, что проект создан и файлы скопированы в этот каталог.
Теперь осталось сделать еще два шага. Нам нужна настраиваемая инициализацияgit
и установить зависимости. Для этого нам понадобятся еще три зависимости:
-
execa
Используется, чтобы позволить нам легко запускать такие вещи, какgit
Такая внешняя команда -
pkg-install
Используется для запуска команд в зависимости от того, что использует пользователь.yarn install
илиnpm install
-
listr
Давайте укажем список задач и предоставим пользователю четкое представление о ходе выполнения
Установите зависимости, выполнив следующую команду:
npm install execa pkg-install listr
обновить позжеmain.js
, добавьте следующий код:
import chalk from 'chalk';
import fs from 'fs';
import ncp from 'ncp';
import path from 'path';
import { promisify } from 'util';
import execa from 'execa';
import Listr from 'listr';
import { projectInstall } from 'pkg-install';
const access = promisify(fs.access);
const copy = promisify(ncp);
async function copyTemplateFiles(options) {
return copy(options.templateDirectory, options.targetDirectory, {
clobber: false,
});
}
async function initGit(options) {
const result = await execa('git', ['init'], {
cwd: options.targetDirectory,
});
if (result.failed) {
return Promise.reject(new Error('Failed to initialize git'));
}
return;
}
export async function createProject(options) {
options = {
...options,
targetDirectory: options.targetDirectory || process.cwd()
};
const templateDir = path.resolve(
new URL(import.meta.url).pathname,
'../../templates',
options.template
);
options.templateDirectory = templateDir;
try {
await access(templateDir, fs.constants.R_OK);
} catch (err) {
console.error('%s Invalid template name', chalk.red.bold('ERROR'));
process.exit(1);
}
const tasks = new Listr([
{
title: 'Copy project files',
task: () => copyTemplateFiles(options),
},
{
title: 'Initialize git',
task: () => initGit(options),
enabled: () => options.git,
},
{
title: 'Install dependencies',
task: () =>
projectInstall({
cwd: options.targetDirectory,
}),
skip: () =>
!options.runInstall
? 'Pass --install to automatically install dependencies'
: undefined,
},
]);
await tasks.run();
console.log('%s Project ready', chalk.green.bold('DONE'));
return true;
}
Этот код будет передан в--git
или пользователь, выбранный в подсказкеgit
беги, когдаgit init
, и будет передано в--install
беги, когдаnpm install
илиyarn
, в противном случае он пропустит обе задачи и уведомит пользователя сообщением о том, что если он хочет автоматическую установку, перейдите в--install
.
Сначала удалите существующую тестовую папку, создайте новую и посмотрите, как она работает. Запустите команду:
create-project typescript --git --install
В вашей папке вы должны увидеть.git
папка иnode_modules
папка, представляющаяgit
был инициализирован, иpackage.json
Зависимости, указанные в, уже установлены.
Поздравляем, ваш первый интерфейс командной строки готов к работе!
Если вы хотите, чтобы ваш код был доступен как фактический модуль, чтобы другие могли повторно использовать вашу логику в своем коде, вам также необходимо добавитьsrc/
добавить файлы подindex.js
, этот файл предоставляетmain.js
Содержание:
require = require('esm')(module);
require('../src/cli').cli(process.argv);
Что дальше?
Теперь, когда ваш код CLI готов, вы можете использовать его и двигаться дальше. Если вы просто хотите использовать его сами и не хотите делиться им с другими, вам нужно продолжать его использовать.npm link
Вот и все. На самом деле бегnpm init project
Попробуйте это, ваш код также будет запущен.
Если вы хотите поделиться своими шаблонами кода с другими, вы можете отправить код на GitHub для справки или, что еще лучше, использоватьnpm publish
подтолкнуть его как пакет кnpm
регистр. Перед публикацией также необходимо убедиться, чтоpackage.json
добавить файлfiles
атрибуты, чтобы указать, какие файлы должны быть опубликованы:
},
"files": [
"bin/",
"src/",
"templates/"
]
}
Если вы хотите проверить, что файл будет опубликован, запуститеnpm pack --dry-run
Затем посмотрите на вывод. использовать послеnpm publish
опубликовать CLI. ты сможешь@dkundel/create-project
Найдите мой проект или попробуйте запуститьnpm init @dkundel/project
.
Есть много других функций, которые вы можете добавить к нему. В моем проекте я также добавил некоторые зависимости для создания для меняLICENSE
,CODE_OF_CONDUCT.md
и.gitignore
. Ты сможешьНайдите исходный код, реализующий эти функции, на GitHub., или ознакомьтесь с упомянутыми выше репозиториями для получения дополнительной функциональности. Если вы найдете библиотеку, которая, по вашему мнению, должна быть указана в статье, которой я не указал, или хотите показать мне свой интерфейс командной строки, просто отправьте мне сообщение!
- Электронное письмо:dkundel@twilio.com
- Твиттер:@dkundel
- Гитхаб:dkundel
- dkundel.com
Вы можете создать еще больше с помощью JavaScript:
- Changelog: Twilio Chat JavaScript SDK
- Sync SDK for JavaScript
- How to Build a Real Time MMS Photostream with Twilio and Socket.IO
- Implementing Chat in JavaScript, Node.js and React Apps
- How to play music over phone calls with Twilio Voice and JavaScript
Если вы обнаружите ошибки в переводе или в других областях, требующих доработки, добро пожаловать наПрограмма перевода самородковВы также можете получить соответствующие бонусные баллы за доработку перевода и PR. начало статьиПостоянная ссылка на эту статьюЭто ссылка MarkDown этой статьи на GitHub.
Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,продукт,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.