[toc]

node 利用命令行交互生成相应模板

  • 创建时间:2019-10-15
  • 测试环境:win10 node-v10.16.1

vue-cli 初始化项目的启发,想探究其原理和自己实现一套类似方法,以便在项目中创建公用模板块。


这里采用三种方式实现

  1. node 自带的 readline
  2. 使用process实现
  3. 第三方包 inquirer

commander.js 用于创建 cli 设置程序版本 -v --version 等命令行 提供了用户命令行输入和参数解析

chalk 设置命令行样式颜色

所有实现方式的完整代码 github 链接open in new window

链接文件结构如下

|-- generatorTemplate.js (生成模板)
|-- readline.js (readline 方式完整代码)
|-- process.js (process 方式完整代码)
|-- inquirer.js (inquirer 方式完整代码)

创建的模板示例:根据用户输入的不同,返回不同结果,包括实现了生成一个文件夹,文件夹内容如下

|--template
   |--css
   |--images
   |--js
     |-- index.js

readline 实现

引入 node 自带的 readline

const readline = require('readline');

初始创建

const rl = readline.createInterface({
    /* 监听可读流 */
    input: process.stdin,
    /* 读取写入的 可写流 */
    output: process.stdout,
    /* 提示信息 */ 
    // prompt: '请输入:'
});

这里会一直监听用户的输入 当输入template时 创建模板

rl.on('line', function(input) {
    if(input === 'template') {
        /* 这里的generator方法参见下方 */
        generatorTemplate.generator()
        rl.close()
    } else if (input === 'pause') {
        rl.pause()
    } else {
        rl.write('please input right: ');
    }
})

完整代码查看 readline.js

更多用法参考: 官方文档 readlineopen in new window

使用process实现

当用户输入的内容为template时,就生成模板

const processFn = () => {
    const handleInput = (input) => {
        if(input === 'student') {
            process.stdout.write('there is student here: hew\n')
        } else if(input === 'template') {
            /* 这里的generator方法参见 */
            generatorTemplate.generator()
            process.stdin.emit('end');
        } else {
            process.stdout.write('some other input message\n')
            process.stdin.emit('end');
        }
    }
    process.stdin.setEncoding('utf-8')
    process.stdin.on('readable', () => {
        let chunk = null;
        while ((chunk = process.stdin.read()) !== null) {         
            if (typeof chunk === 'string') {
                chunk = chunk.slice(0, -2);
                if(chunk) {
                    handleInput(chunk)
                } else {
                    process.stdin.emit('end');
                }
            }
        }
    })
    process.stdin.on('end', () => {
        process.stdout.write('结束\n');
        process.exit()
    })
}

完整代码查看 process.js

更多用法参考: 官方文档 processopen in new window

使用 inquirer

https://github.com/JohnApache/inquirer-usage-doc 文档说明

9以上版本 不能用 require 引入

expand 会把所有的 choice 的key 集合起来提示,然后用户输入对应的key,显示对应key的name值

inquirer
    .prompt([
        {
            type: 'confirm',
            name: 'toBeDelivered',
            message: '是否生成模板?', // 这里的值可以用 chalk.blueBright(‘xxx’),
            prefix: '|-', // 问题描述前置信息,可以设置以去掉开头显示的问号
            suffix: ':', // 最终输出 |- 是否生成模板? :
            default: false
        },
        {
            type: "input",
            name: "input",
            message: '请输入',
            prefix: '|-',
            suffix: ':',
            transformer(value) { // 修改用户的输入内容格式等,但不会修改实际的输入值,只影响显示
                return chalk.cyan(value);
            },
            validate: function(value) {
                if(/^a$/ig.test(value)) {
                    return true
                } else {
                    /* 校验务必采用返回 error 不然不会有错误提示 */
                    return chalk.red(new Error('请输入正确'))
                }
            }
        },
        {
            type: 'list',
            name: 'configType',
            message: '请选择配置操作',
            when: h => h.configType === 0,// 当前面答案符合某个条件时,显示当前问题
            choices: [
                { name: '1. 配置页面颜色', value: 0, },
                { name: '2. 配置按钮布局', value: 1, }
            ],
        },
        {
            type: 'checkbox',
            name: 'choices',
            message: 'Is this for delivery?',
            default: 'check',
            choices: ['yes', 'no']
        }
    ],
    // {
    //     confirm: true // 这里放问题答案,如果在此配置,对应的问题将直接跳过,默认使用该答案
    // }
    )
    .then(answers => {
        console.log(answers);
        /* 输出值为:{ toBeDelivered: true, choices: [ 'name' ] } */
        if(answers.toBeDelivered && answers.choices[0] === 'yes') {
            /* 这里的generator方法参见下方 */
            generatorTemplate.generator();
        } else {
            console.log('不生成模板');
        }
    }).catch((error) => {
        if (error.isTtyError) {
        // Prompt couldn't be rendered in the current environment
        console.log(error);
        } else {
        // Something else went wrong
        console.log(error);
        }
    });

完整代码查看 inquirer.js

更多用法参考: 官方文档 inquireropen in new window

调用的生成模板方法 (generator 方法)

generator.js

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

const jsStr = 
`const a = '';
const b = 1;
export default {
    a: a,
    b: b
}
`

function generator() {
    fs.mkdirSync(path.join(__dirname, 'template'));
    fs.mkdirSync(path.join(__dirname, 'template', 'css'));
    fs.mkdirSync(path.join(__dirname, 'template', 'js'));
    fs.mkdirSync(path.join(__dirname, 'template', 'images'));
    
    fs.writeFileSync(path.join(__dirname, 'template', 'js', 'index.js'), jsStr, 'utf-8')
}

exports.generator = generator;

欢迎交流 Githubopen in new window

Last Updated:
Contributors: Warren