Разрабатывайте с помощью инструмента кли, в который вы влюбитесь однажды

Node.js
Разрабатывайте с помощью инструмента кли, в который вы влюбитесь однажды

написать впереди

Недавно взял на себя задачу — с помощью nodejs разработать cli инструмент для внутреннего использования в компании, короче можно ввести строку команд для быстрого построения структуры проекта, а можно через разные команды импортировать разные файлы.

учиться

сначала на основеnodeсреде, то нам нужно знать, что такое cli? Cli — это аббревиатура интерфейса командной строки, то есть инструмент командной строки, обычно используемыйvue-cli,create-react-app,express-generatorи т. д. являются инструментами кли.

обзор

Создаватьexercise-cliкаталог и используйте cmd для входа в каталог:

mkdir exercise-cli && cd exercise-cli

Создайте новый в этом каталогеindex.js:

//index.js
console.log('谢邀,人在美国,刚下飞机。');

Запустите index.js с узлом:

Это основное использование узла, так как же использовать пользовательскую командную строку для вывода этого предложения?

зажигание

использоватьnpm initСоздайтеpackage.json, и нажмите Enter до конца. Конечно, вы также можете настроить соответствующую информацию. Если вам интересно, вы можете выбрать самостоятельно:

Каталог теперь создается автоматическиpackage.jsonдокумент:

{
  "name": "exercise-cli",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

сейчас наpackage.jsonдобавить поля вbin, используемый для хранения исполняемого файла, наш исполняемый файл здесь — index.js, поэтому конфигурация следующая:

"bin":{
    "exercise-cli":"./index.js"
},

На этом этапе мы настраиваемexercise-cliкоманда для выполненияindex.jsфайл, который должен бытьindex.jsдобавить заголовок файла#!/usr/bin/env node, пусть система сама найдет исполнителя ноды. Что касается того, что это за штука, Baidu придумал этовещь, для справки.

//index.js
#!/usr/bin/env node
console.log('谢邀,人在美国,刚下飞机。');

Затем введите в cmdnpn linkилиnpm install -gУстановите текущий проект в глобальную среду, чтобы его можно было использовать напрямую.exercise-cliдля запуска файла:

Чтобы узнать больше, добавьте имя скрипта в поле scripts файла package.json:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "exercise":"exercise-cli"
 }

ввод командной строкиnpm run exercise, тот же выводindex.jsсодержание вvue-cliизnpm run dev,npm run buildБудете ли вы думать об этом?

снять

Это выглядит примерно так, давайте посмотрим, как он генерирует шаблоны проектов. Идея состоит в том, чтобы использовать папку шаблонов для сохранения шаблонов проекта, затем создать каталог проекта с помощью fs.mkdir() и, наконец, скопировать файлы из папки шаблонов в проект. Локальный каталог шаблонов показан ниже:

1. Скопируйте файл

Сцена моделирования: поместите локальные шаблоны вvue.min.jsСкопируйте во вновь созданный шаблон проекта. Создайте новый общедоступный каталог во вновь сгенерированном шаблоне проекта, создайте новый каталог js в этом каталоге и поместитеvue.min.jsпройти черезcopyTemplate()Метод копируется из шаблонов во вновь созданный каталог js:

//index.js
#!/usr/bin/env node

var fs = require('fs');
var path = require('path');

// 复制文件
function copyTemplate (from, to) {
  from = path.join(__dirname, 'templates', from);
  console.log(from);
  write(to, fs.readFileSync(from, 'utf-8'))
}
function write (path, str, mode) {
  fs.writeFileSync(path, str)
}
// 新建目录
function mkdir (path, fn) {
  fs.mkdir(path, function (err) {
    fn && fn()
  })
}

var PATH = ".";
mkdir(PATH+'/public',function(){
	mkdir(PATH + '/public/js',function () {
		copyTemplate("/js/vue.min.js", PATH + '/public/js/vue.min.js');
	})
})

Откройте любую папку с вводом cmdexercise-cli, папка будетpublic\js\vue.min.js:

2. Скопируйте папку

Мы научились копировать файлы, так как скопировать всю папку, например, я хочу скопировать всю папку js под шаблонами в только что сгенерированный шаблон проекта, что мне делать? Если есть потребность - есть план. Можем пройтись по всей папке и судить о пройденном пути. Если это файл, то он будет скопирован напрямую, а если это папка, то рекурсивно:

//index.js
// 复制目录
var copy=function(src,dst){
    let paths = fs.readdirSync(src); //同步读取当前目录(只能读取绝对路径,相对路径无法获取)
    paths.forEach(function(path){
        var _src=src+'/'+path;
        var _dst=dst+'/'+path;
        fs.stat(_src,function(err,stats){  //stats  该对象 包含文件属性
            if(err)throw err;
            if(stats.isFile()){ //如果是个文件则拷贝 
                let  readable=fs.createReadStream(_src);//创建读取流
                let  writable=fs.createWriteStream(_dst);//创建写入流
                readable.pipe(writable);
            }else if(stats.isDirectory()){ //是目录则 递归 
                checkDirectory(_src,_dst,copy);
            }
        });
    });
}
var checkDirectory=function(src,dst,callback){
    fs.access(dst, fs.constants.F_OK, (err) => {
        if(err){
            fs.mkdirSync(dst);
            callback(src,dst);
        }else{
            callback(src,dst);
        }
      });
};

mkdir(PATH+'/public',function(){
	mkdir(PATH + '/public/js',function () {
		checkDirectory('C:/Users/Administrator/Desktop/vue-3.0/nodeTest/exercise/templates/js',PATH+'/public/js',copy);
	})
})

Все еще ищу папку, чтобы открыть cmd и войтиexercise-cli, общедоступный каталог будет создан в этой папке, и весь файл js в шаблонах будет создан в этом каталоге:

3. Получите аргументы командной строки

Обычно мы используем параметры при использовании инструментов командной строки, таких какwebpack -p, express -eподождите, вот и мыexercise-cliнастроить-l, когда используешьexercise-cli -l, добавьте слойJS.

мы можем использоватьprocess.argvчтобы получить аргументы командной строки,process.argvпредставляет собой массив параметров, первый элемент — абсолютный путь к node.exe, второй элемент — абсолютный путь для выполнения js, используйтеprocess.argv.slice(2)Вы можете получить массив входных параметров.

//index.js
console.log(process.argv);

Проверьте, какие параметры были введены в команду, перебирая массив параметров. Если введены предустановленные параметры, соответствующие атрибуты добавляются в объект конфигурации, и при создании файла решается, следует ли копировать файл шаблона в проект в соответствии с конфигом.

var config = {};
process.argv.slice(2).forEach(item=>{
	if(item=="-l"){
		config.layer = true;
	}
})
var PATH = ".";
mkdir(PATH+'/public',function(){
	mkdir(PATH + '/public/js',function () {
		// copyTemplate("/js/vue.min.js", PATH + '/public/js/vue.min.js');
		checkDirectory('C:/Users/Administrator/Desktop/vue-3.0/nodeTest/exercise/templates/js',PATH+'/public/js',copy);
		if(config.layer){
			checkDirectory('C:/Users/Administrator/Desktop/exercise-cli/templates/layer',PATH+'/public/js',copy);
			//此处注意layerJS存放在templates中的路径。
		}
	})
})
console.log('拷贝成功');

Откройте cmd в любой папке и введитеexercise-cli -l, выполнение успешно, каталог layerJS добавляется в каталог js:

ускорить

начальный command.js

На самом деле в узле есть инструментарий, который может быстро разрабатывать инструменты командной строки, этоcommander.js.

Сначала установите его глобально:

npm install commander -g

См. пример:

var program = require('commander');
program
    .version('1.0.0','-v, --version')
    .command('check [checkname]')
    .alias('c')
    .description('yo yo check now')
    .option('-a, --name [moduleName]', '模块名称')
    .action((checkname,option) => {
        console.log('指令 install 后面跟的参数值 checkname: ' + checkname);
        console.log(option);
        // 获得了参数,可以在这里做响应的业务处理
    })
    	//自定义帮助信息
    .on('--help', function() {
        console.log('  下面我随便说两句:')
        console.log('')
        console.log('$ 人有多大胆,母猪多大产,i love xx')
        console.log('$ 广阔天地,大有所为,呱~')
    })
program.parse(process.argv)

Выполнение командной строки:

После прочтения вывода вы запутались, не волнуйтесь, давайте посмотрим, что это такое:

  • version - определяет номер версии командной программы, .version('0.0.1', '-v, --version'), номер версии первого параметра обязателен, второй параметр можно не указывать, по умолчанию -V и -- версия
  • command — определяет команду командной строки, за которой следует имя, разделенное пробелами, например .command('app [name]')
  • псевдоним — определите более короткую команду командной строки, например, $ упражнение-cli c эквивалентно выполнению команды
  • description - описание, оно будет отображаться в справке
  • option – определяет параметр. Он принимает четыре параметра.В первый параметр он может ввести короткое имя -a и длинное имя -name, разделенные | или , при использовании в командной строке эти два эквивалентны, разница заключается в том, что параметр можно получить через обратный вызов в программе, второй параметр это описание, которое будет отображаться в справочной информации, третий параметр это функция обратного вызова, параметр, который она получает, представляет собой строку, иногда нам нужно создать несколько модулей, вам нужен обратный вызов для обработки; четвертый параметр является значением по умолчанию
  • действие — зарегистрировать функцию обратного вызова, здесь следует отметить, что обратный вызов в настоящее время не поддерживает переменные объявления let
  • parse — используется для разбора process.argv, установки опций и запускающих команд, пример использования: .parse(process.argv)

Увидев это, я имею более-менее общее представление о том, как писать инструменты командной строки, я просто говорю об этом, не практикуя слова, и сам практикую: используйте command.js для завершения предыдущего абзаца.3.接收命令行参数пример в .


Разделительная линия (следующие углубленные и мелкие части будут обновлены 2019.4.30)

Погрузитесь в inquirer.js

При создании скаффолдинга мы обнаружим, что многие скаффолдинги требуют от нас частого взаимодействия с командной строкой, точно так же, как когда мы начинаем использоватьnpm initКогда время одинаковое, то как добиться взаимодействия с командной строкой? В настоящее времяinquirer.jsдебют.

//命令行安装
npm install inquirer
//index.js引入
var inquirer = require('inquirer');
  1. базовая грамматика
var inquirer = require('inquirer');
inquirer.prompt([/* Pass your questions in here */]).then(function (answers) {
    // Use user feedback for... whatever!! 
})
  1. Подробное объяснение параметра
  • тип: указывает тип вопроса, в том числе: ввод, подтверждение, список, необработанный список, расширение, флажок, пароль, редактор;
  • имя: переменная, в которой хранится ответ на текущий вопрос;
  • сообщение: описание проблемы;
  • по умолчанию: значение по умолчанию;
  • варианты: список вариантов, доступных для некоторых типов, и содержит разделитель;
  • Проверьте: подтвердить ответ пользователя;
  • filter: фильтровать ответ пользователя и возвращать обработанное значение;
  • преобразователь: обработать эффект отображения ответа пользователя (например: изменить шрифт или цвет фона ответа), но не повлияет на содержание окончательного ответа;
  • когда: По ответам на предыдущие вопросы определить, нужно ли отвечать на текущий вопрос;
  • pageSize: изменить количество отображаемых строк для определенных типов;
  • префикс: изменить префикс сообщения по умолчанию;
  • суффикс: изменить суффикс сообщения по умолчанию.
  1. Анализ случая

существует.actionВведите следующее в функцию обратного вызова:

// 获得了参数,可以在这里做响应的业务处理
var prompList = [
	{
		type:'input',
		message:'姓名',
		name:'name'
	},{
		type:'input',
		message:'手机号',
		name:'phone',
		validate:val=>{
			if(val.match(/\d{11}/g)){
				return true
			}
			return '请输入11位数字'
		}
	},{
		type:'confirm',
		message:'是否参加本次考核?',
		name:'assess',
		prefix:'前缀'
	},{
		type:'confirm',
		message:'是否同意本次考核须知?',
		name:'notice',
		suffix:'后缀',
		when:answers=>{
			return answers.assess
		}
	},{
		type:'list',
		message:'欢迎来到本次考核,请选择学历:',
		name:'eductionBg',
		choices:[
			"大专",
			"本科",
			"本科以上"
		],
		filter:val=>{//将选择的内容后面加学历
			return val+'学历'
		}
	},{
		type:'rawlist',
		message:'请选择你爱玩的游戏:',
		name:'game',
		choices:[
			"LOL",
			"DOTA",
			"PUBG"
		]
	},{
		type:'expand',
			message:'请选择你喜欢的水果:',
			name:'fruit',
			choices: [
			{
				key: "a",
				name: "Apple",
				value: "apple"
			},
			{
				key: "O",
				name: "Orange",
				value: "orange"
			},
			{
				key: "p",
				name: "Pear",
				value: "pear"
			}
		]
	},{
		type:'checkbox',
		message:'请选择你喜欢的颜色:',
		name:'color',
		choices:[
			{
				name: "red"
			},
			new inquirer.Separator(), // 添加分隔符
			{
				name: "blur",
				checked: true // 默认选中
			},
			{
				name: "green"
			},
			new inquirer.Separator("--- 分隔符 ---"), // 自定义分隔符
			{
				name: "yellow"
			}
		]
	},{
		type:'password',
		message:'请输入你的游戏密码:',
		name:'pwd'
	}
	
]
inquirer.prompt(prompList).then(answers=>{
	console.log(answers);
})

Взаимодействие с командной строкой выглядит следующим образом:

Простой мел.js

Наконец, мы представляемchalkЭтот модуль для украшения командной строки отличается малым весом, высокой производительностью и низкой стоимостью обучения. Продолжайте вводить мел в приведенном выше примере для вывода:

//命令行安装
npm install chalk
//index.js引入
var chalk = require('chalk');

В запросчике распечатайте следующее:

inquirer.prompt(prompList).then(answers=>{
	console.log(answers);
	console.log(chalk.green('考核完成'))//字体绿色
	console.log(chalk.blue('你最棒了'))//字体蓝色
	console.log(chalk.blue.bgRed('五一放假喽')) //支持设置背景
	console.log(chalk.blue(answers))
})

Командная строка в итоге выглядит так:

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

посадка

Чтобы позволить другим установить ваш инструмент cli, вам нужно опубликовать его на npm, сначала вофициальный сайт нпмСоздайте учетную запись (обратите внимание, что требуется подтверждение электронной почты), введите в командной строкеnpm adduser, и поочередно введите зарегистрированный логин, пароль, адрес электронной почты. Затем введитеnpm publishПросто:

входитьnpm install -g exercise-cliилиnpm install exercise-cliУстановите свой cli и почувствуйте его прелесть.

Код загружен намой GitHub, добро пожаловать в Форк.

благодарный