Давайте узнаем, как сделать CLI с Node

Node.js внешний интерфейс Командная строка JavaScript

Что такое интерфейс командной строки

воспитыватьCLI, не могу не вспомнитьvue-cliа такжеangular-cli, они основаны наNodeинструмент командной строки.

Зачем разрабатыватьCLI

Предположим, вы сейчас создаете новый проект с той же конфигурацией, что и предыдущий проект. без тебяCLI, вы можете сделать это только путем копирования и вставки. Однако, когда у вас естьCLI, вы можете выполнить эти шаги с помощью команд. Конечно, можно сказать просто создать новый проект, разрабатывать еще один совершенно не обязательно.CLIинструмент. Что делать, если вы хотите создать n новых проектов? В это время естьCLIи нетCLIразница проявляется.

как разработатьCLI

Подготовить

разрабатыватьCLI, потребуются следующие инструменты:

Начинать

Создайте новую папку, назовите ееdemo-cli, а внутри папкиnpm init. существуетdemo-cliВнутри папки создайте новыйbinпапку и создайте новую в этой папкеindex.jsдокумент. Далее откройтеdemo-cliв папкеpackage.jsonфайл и добавьте в него следующую команду.

{
    "bin": {
        "demo": "./bin/index.js"
    }
}

Этот код означает, что при использованииdemoКогда команда будет выполнена, она будет выполненаbinв папкеindex.jsдокумент.

В это время мыindex.jsфайл, напишите следующий код.


#!/usr/bin/env node

console.log('hello CLI');

существуетdemo-cliзапустить в каталогеnpm link,demo, на этот раз вы найдете вывод консолиhello CLI.

Примечание:

  • #!/usr/bin/env nodeуказать операционной системе использоватьNodeзапустить этот файл
  • npm linkОсновная роль заключается в развитииnpmЧто касается модулей, мы будем отлаживать их во время разработки. В настоящее время,npm linkЭто пригодилось.

шаг за шагом

  1. существуетindex.jsВнутри файла напишите следующий код.
#!/usr/bin/env node

const program = require('commander');

program
    .version('1.0.0', '-v, --version')
    .command('init <dir>', 'generate a new project')
    .parse(process.argv);

commanderобеспечивает использованиеnode.jsразвивать возможности командной строки. мы можем пройтиcommanderизoptionметод определенияcommanderoptions, конечно, эти определенные параметры также будут использоваться в качестве справочной документации команды.

  • version: Используется для определения номера версии.commanderПомогите нам добавить по умолчанию-V, --versionопции. Конечно, мы также можем сбросить его.
  • command:<>Требуются делегаты,[]Представитель необязателен. когда.command()С параметром описания его нельзя использовать.action(callback)для обработки подкоманды, иначе произойдет ошибка. это говоритcommander, вы будете использовать отдельные исполняемые файлы в качестве подкоманд.
  • parse: разборprocess.argv, данные после парсинга будут храниться вnew Command().argsв массиве.process.argvСодержимое, хранящееся в нем, следующее:

Итак, мы можем пройтиprogram.args[0]вывезтиdirценность .

Вопрос: почему когдаcommandнет параметров описания, иparseМетод, использующий цепной вызов, сообщит об ошибке? (догадка:commandимеютdescпараметр, возвратthis, когда нетdescпараметр, возвращает новый объект,согласно сAPI Documentпредполагаемый)

```js
// 正确
program
    .version('1.0.0', '-v, --version')
    .command('init <dir>', 'generate a new project')
    .action(function(dir, cmd){
        console.log(dir, cmd)
    })
    .parse(process.argv);

// 正确
program
    .version('1.0.0', '-v, --version')
    .command('init <dir>', 'generate a new project')
    .action(function(dir, cmd){
        console.log(dir, cmd)
    })
program.parse(process.argv);

// 正确
program
    .version('1.0.0', '-v, --version')
    .command('init <dir>')
    .action(function(dir, cmd){
        console.log(dir, cmd)
    })
program.parse(process.argv);

// 错误
program
    .version('1.0.0', '-v, --version')
    .command('init <dir>')
    .action(function(dir, cmd){
        console.log(dir, cmd)
    })
    .parse(process.argv);
```
  1. существуетbinСоздать в файлеdemo-init.jsфайл, часть кода выглядит следующим образом:

#!/usr/bin/env node

const shell = require('shelljs');
const program = require('commander');
const inquirer = require('inquirer');
const download = require('download-git-repo');
const ora = require('ora');
const fs = require('fs');
const path = require('path');
const spinner = ora();

program.parse(process.argv);

let dir = program.args[0];

const questions = [{
    type: 'input',
    name: 'name',
    message: '请输入项目名称',
    default: 'demo-static',
    validate: (name)=>{
        if(/^[a-z]+/.test(name)){
            return true;
        }else{
            return '项目名称必须以小写字母开头';
        }
    }
}]

inquirer.prompt(questions).then((answers)=>{
    // 初始化模板文件
    downloadTemplate(answers);
})

function downloadTemplate(params){
    spinner.start('loading');
    let isHasDir = fs.existsSync(path.resolve(dir));
    if(isHasDir){
        spinner.fail('当前目录已存在!');
        return false;
    }
    // 开始下载模板文件
    download('gitlab:git.gitlab.com/demo-static', dir, {clone: true}, function(err){
        if(err){
            spinner.fail(err);
        };
        updateTemplateFile(params);
    })
}

function updateTemplateFile(params){
    let { name, description } = params;
    fs.readFile(`${path.resolve(dir)}/public/package.json`, (err, buffer)=>{
        if(err) {
            console.log(chalk.red(err));
            return false;
        }
        shell.rm('-f', `${path.resolve(dir)}/.git`);
        shell.rm('-f', `${path.resolve(dir)}/public/CHANGELOG.md`);
        let packageJson = JSON.parse(buffer);
        Object.assign(packageJson, params);
        fs.writeFileSync(`${path.resolve(dir)}/public/package.json`, JSON.stringify(packageJson, null, 2));
        fs.writeFileSync(`${path.resolve(dir)}/README.md`, `# ${name}\n> ${description}`);
        spinner.succeed('创建完毕');
    });
}

  • inquirerВ основном он обеспечивает функцию интерактивных команд.validateвернутьtrueУказывает, что входное значение допустимо для проверки. Если возвращается какая-либо строка, она будет возвращена вместо стандартного сообщения об ошибке.
  • пройти черезNodeсерединаfsмодуль, чтобы определить, существует ли уже папка.

    path.resolveметод используется для преобразования относительных путей в абсолютные пути. Он может принимать несколько параметров, указывая путь, который нужно ввести по очереди, пока последний параметр не будет преобразован в абсолютный путь. Если абсолютный путь не может быть получен в соответствии с параметрами, в качестве ссылки используется текущий путь. За исключением корневого каталога, возвращаемое значение этого метода не имеет завершающей косой черты.

Ссылаться на