Разрабатывайте простые инструменты формирования шаблонов с помощью Node.js.

Node.js внешний интерфейс JavaScript

предисловие

Скаффолдинг вроде vue-cli, react-native-cli и т. д. с которыми мы знакомы, просто нужно ввести простые командыvue init webpack project, вы можете быстро помочь нам создать первоначальный проект. В реальной работе мы можем настроить собственные леса, чтобы повысить эффективность нашей работы.

Зачем нужны подмости?

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

идеи

Чтобы разработать строительные леса, мы должны сначала прояснить свое мышление.Как работают строительные леса? Мы можем извлечь уроки из основных идей vue-cli. vue-cli помещает шаблон проекта в git, а затем загружает различные шаблоны в соответствии с действиями пользователя при запуске и отображает их через механизм шаблонов для создания проекта. Таким образом, шаблон и леса можно разделить, чтобы их можно было поддерживать отдельно.Даже если шаблон изменится, необходимо загрузить только последний шаблон, и последний проект может быть сгенерирован без необходимости обновления пользователем шаблонов. . Затем его можно развивать в соответствии с этой идеей.

сторонняя библиотека

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

  • commander.js, который может автоматически анализировать команды и параметры для обработки команд, введенных пользователями.
  • download-git-repo, загрузите и извлеките репозиторий git для загрузки шаблонов проектов.
  • Inquirer.js, набор универсальных пользовательских интерфейсов командной строки для взаимодействия с пользователями.
  • handlebars.js, механизм шаблонов, который динамически заполняет файл информацией, предоставленной пользователем.
  • ora, если процесс загрузки длительный, его можно использовать для отображения анимационного эффекта во время загрузки.
  • chalk, вы можете добавить цвет к шрифту терминала.
  • log-symbolsи такие значки, как √ или ×, могут отображаться на терминале.

Инициализировать проект

Сначала создайте пустой проект с временным именем okii-cli, затем создайте новый файл index.js, а затем выполните npm init для создания файла package.json. Наконец, установите зависимости, необходимые выше.

npm install commander download-git-repo inquirer handlebars ora chalk log-symbols -S

Обработать командную строку

Node.js имеет встроенную поддержку операций командной строки.Поле bin в package.json может определять имя команды и связанный с ней исполняемый файл. Теперь добавьте содержимое bin в package.json:

{
  "name": "okii-cli",
  "version": "1.0.0",
  "description": "基于node的脚手架工具",
  "bin": {
    "okii": "index.js"
  },
  ...
}

Затем определите команду инициализации в index.js:

#!/usr/bin/env node
const program = require('commander');

program.version('1.0.0', '-v, --version')
       .command('init <name>')
       .action((name) => {
           console.log(name);
       });
program.parse(process.argv);

передачаversion('1.0.0', '-v, --version')Добавит к команде -v и --version, с этими параметрами можно распечатать номер версии.
передачаcommand('init <name>')Определите команду init, а name — обязательный параметр, то есть имя проекта.
action()Это поведение будет происходить при выполнении команды init.Здесь выполняется процесс создания проекта, и пока печатается только имя.
На самом деле здесь уже можно выполнить команда инициализации. Давайте протестируем его и выполним в том же каталоге okii-cli:

node ./okii-cli/index.js init HelloWorld

Вы можете видеть, что инструмент командной строки также распечатываетHelloWorld, тогда понятно,action((name) => {})Здесь имя параметра, введите имя проекта, это реализация команды инициализации.

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

Скачать шаблон

download-git-repo поддерживает загрузку репозиториев с Github, Gitlab и Bitbucket, Информацию об использовании каждого из них см. в официальной документации.

Поскольку это проект компании, репозиторий шаблонов размещается на Gitlab, затем в action() выполняется операция по скачиванию шаблона:

#!/usr/bin/env node
const program = require('commander');
const download = require('download-git-repo');

program.version('1.0.0', '-v, --version')
       .command('init <name>')
       .action((name) => {
           download('http://xxxxxx:9999:HTML5/H5Template#master', name, {clone: true}, (err) => {
                console.log(err ? 'Error' : 'Success')
           })
       });
program.parse(process.argv);

download()Первый параметр — это адрес склада, но он немного другой. Фактический адрес складаhttp://xxxxxx:9999/HTML5/H5Template#master , вы можете видеть, что '/' после номера порта должен быть записан как ':' в параметре, #master представляет имя ветки, разные шаблоны могут быть размещены в разных ветках, и ветку можно легко изменить. Вы можете скачать различные файлы шаблонов. Второй параметр это путь, выше мы создаем прямо под текущим путем В папке name хранятся шаблоны, или вы можете использовать дополнительные каталоги, такие какtest/${name}

взаимодействие с командной строкой

Функция взаимодействия с командной строкой может задавать вопросы пользователю после того, как пользователь выполнит команду инициализации, получит ввод пользователя и выполнит соответствующую обработку. Это реализовано с помощью inquirer.js.

const inquirer = require('inquirer');
inquirer.prompt([
    {
        type: 'input',
        name: 'author',
        message: '请输入作者名称'
    }
]).then((answers) => {
    console.log(answers.author);
})

Как видно из приведенного здесь примера, вопрос помещается в prompt(), тип вопроса является входным, который является типом ввода, имя является ключом в объекте ответа, сообщение является вопросом, а ответ, введенный пользователем, находится в ответах. Это так просто. Дополнительные настройки параметров см. в официальной документации.

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

шаблон рендеринга

Здесь используйте синтаксис handlebars, чтобы внести некоторые изменения в файл package.json в шаблоне репозитория HTML5/H5Template.

{
  "name": "{{name}}",
  "version": "1.0.0",
  "description": "{{description}}",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "{{author}}",
  "license": "ISC"
}

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

program.version('1.0.0', '-v, --version')
.command('init <name>')
.action((name) => {
    inquirer.prompt([
    {
        name: 'description',
        message: '请输入项目描述'
    },
    {
        name: 'author',
        message: '请输入作者名称'
    }
    ]).then((answers) => {
        download('xxxxx#master',name,{clone: true},(err) => {
            const meta = {
                name,
                description: answers.description,
                author: answers.author
            }
            const fileName = `${name}/package.json`;
            const content = fs.readFileSync(fileName).toString();
            const result = handlebars.compile(content)(meta);
            fs.writeFileSync(fileName, result);
        })
    })
});

Здесь используется файловый модуль fs из node.js, а шаблон после рендеринга руля перезаписывается в файл.

визуальное благоустройство

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

const ora = require('ora');
// 开始下载
const spinner = ora('正在下载模板...');
spinner.start();

// 下载失败调用
spinner.fail();

// 下载成功调用
spinner.succeed();

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

const chalk = require('chalk');
console.log(chalk.green('项目创建成功'));
console.log(chalk.red('项目创建失败'));

Помимо добавления цвета к печатным сообщениям, вы можете использовать символы журнала для префикса сообщений такими значками, как √ или ×.

const chalk = require('chalk');
const symbols = require('log-symbols');
console.log(symbols.success, chalk.green('项目创建成功'));
console.log(symbols.error, chalk.red('项目创建失败'));

Полный пример

#!/usr/bin/env node
const fs = require('fs');
const program = require('commander');
const download = require('download-git-repo');
const handlebars = require('handlebars');
const inquirer = require('inquirer');
const ora = require('ora');
const chalk = require('chalk');
const symbols = require('log-symbols');

program.version('1.0.0', '-v, --version')
    .command('init <name>')
    .action((name) => {
        if(!fs.existsSync(name)){
            inquirer.prompt([
                {
                    name: 'description',
                    message: '请输入项目描述'
                },
                {
                    name: 'author',
                    message: '请输入作者名称'
                }
            ]).then((answers) => {
                const spinner = ora('正在下载模板...');
                spinner.start();
                download('http://xxxxxx:9999:HTML5/H5Template#master', name, {clone: true}, (err) => {
                    if(err){
                        spinner.fail();
                        console.log(symbols.error, chalk.red(err));
                    }else{
                        spinner.succeed();
                        const fileName = `${name}/package.json`;
                        const meta = {
                            name,
                            description: answers.description,
                            author: answers.author
                        }
                        if(fs.existsSync(fileName)){
                            const content = fs.readFileSync(fileName).toString();
                            const result = handlebars.compile(content)(meta);
                            fs.writeFileSync(fileName, result);
                        }
                        console.log(symbols.success, chalk.green('项目初始化完成'));
                    }
                })
            })
        }else{
            // 错误提示项目已存在,避免覆盖原有项目
            console.log(symbols.error, chalk.red('项目已存在'));
        }
    })
program.parse(process.argv);

Эффект следующий:

После завершения вы можете опубликовать скаффолдинг в npm, установить его глобально с помощью -g и выполнить на своем компьютере.okii init [name]для инициализации проекта, который завершает простой инструмент создания лесов.

Еще статьи:lin-xin/blog