工做效率upup,一块儿来实现一个Node.js-CLI开发工具吧

前言

咱们平时项目开发中,常常会有不少相似的代码文件,而咱们在使用的时候也会常常的去复制粘贴。为此我以前也写过一篇文章,探讨过提升开发效率的方法,可是说实话,也并非很好用。css

看现在火热的前端框架,都有本身的CLI工具,例如Vue CLI,creat-react-app等等,搭建项目十分的方便。因此我也在想,要不也实现一个CLI工具,不必定要和前面几个那样高大上,但只要能提升工做的效率,就值得试一试。前端

初始化项目

首先,咱们要打开CLI界面,用npm初始化一个项目:vue

npm init

package.jsonnode

{
  "name": "mycli",
  "version": "1.0.0",
  "description": "A cli-demo",
  "main": "index.js",
  "author": "xmanlin",
  "license": "MIT"
}

里面一些用不上都已经去掉。react

自定义命令

相信不少小伙伴在使用 npm 初始化项目的时候,或者在用 Vue CLI 搭建项目的时候,会发现它们有一个共同点——都有本身个性化的命令,感受有点酷炫。那么咱们怎么才能实现本身的命令呢,很简单,在 package.json 添加 bingit

{
  "name": "mycli",
  "version": "1.0.0",
  "description": "A cli-demo",
  "main": "index.js",
  "bin": {
    "mycli": "./index.js"
  },
  "author": "xmanlin",
  "license": "MIT"
}

package.json中的 bin 的做用就是可让设置的 mycli 成为一个可执行命令,而命令所执行的文件就是后面的 index.js ,这些均可以根据本身的想法来定。接着咱们要继续对 index.js 进行修改:github

index.jsnpm

#!/usr/bin/env node

console.log("执行成功")

这里的第一行很重要,这里代表 index.js 是 node 可执行文件。json

设置完成后,就能够全局安装咱们的CLI工具了:api

npm install -g
+ mycli@1.0.0
added 1 package from 1 contributor in 0.12s

能够看见全局安装成功,最后咱们试试咱们的命令:

mycli

输出:

执行成功

交互式命令行

刚刚小伙伴们在进行命令行操做的时候,使用了不一样选项的命令,例如 npm initnpm install -g ,其中包含一些交互式的,好比在初始化项目时, npm init 提供一些输入问答形式的命令。接下来,咱们就来为本身的CLI工具添加这些相似的命令。

咱们能够依赖两个库进行咱们的开发:commander.jsInquirer.js

  • commander.js:完整的 node.js 命令行解决方案。咱们能够利用它,快速的编写咱们的命令行,自定义化操做。
  • Inquirer.js:是常规交互式命令行用户接口的集合,提供给 Node.js 一个方便嵌入,漂亮的命令行接口。咱们能够用来快速进行交互式命令行的编写。

这两个库的具体用法,这里就过多的介绍,小伙伴们能够点击上面名字的连接去熟悉一下,花不了太多时间,实际用起来也不难,后面那个没有中文Readme,可是不妨碍你们会搜索呀~对不对。

定义选项

咱们首先来实现相似于 npm -vnode -v这样相似的命令选项。

首先安装commander.js:

npm install commander

而后引入 commander.js 并对 index.js 进行修改

#!/usr/bin/env node

const { program } = require('commander');

// 字符串分割为数组的方法
function strToArr(value, preValue){
    return value.split(',')
}
// cli版本
program.version(require('./package').version, '-v, --version', 'cli的最新版本');
// 设置选项
program
    .option('-d, --debug', '调试一下')
    .option('-l, --list <value>', '把字符串分割为数组', strToArr)
    .action((options, command) => {
        // 进行逻辑处理
        if(options.debug) {
            console.log("调试成功")
        }
        if(options.list !== undefined) {
            console.log(options.list)
        }
    });

// 处理命令行输入的参数
program.parse(process.argv);

咱们来试试刚刚设置的命令选项:

mycli -d

输出:

调试成功

输入:

mycli -l 1,2,3

输出:

[ '1', '2', '3' ]

在commander.js里面已经给咱们定义好了 --help 选项:

mycli -h

输出:

Usage: index [options]

Options:
  -v, --version       cli的最新版本
  -d, --debug         调试一下
  -l, --list <value>  把字符串分割为数组
  -h, --help          display help for command

利用 --help 选项,咱们能够很清楚的了解到 mycli 中已有多少命令。

设置子命令

在项目开发中,咱们有时会用到相似于 npm run xxx 这样的命令,其中run就至关于npm的子命令。这里咱们也能够给mycli设置相似的子命令:

const { program } = require('commander');

...

// 建立文件命令行
program
    .command('create <filename>')
    .description('建立一个文件')
    .action((filename) => {
        console.log(filename)
    })
    
...
// 处理命令行输入的参数
program.parse(process.argv);

command('create <filename>') 就是建立了一个 mycli 的 create 子命令,后面跟了一个必填参数。

输入:

mycli create file

输出

file

子命令建立成功。

利用命令行建立项目文件

咱们如今可以定义选项,设置命令了。接下来咱们就能够实际作点东西,利用命令行来建立项目的文件。

简单的设计一个流程:
建立文件流程

建立模板文件

咱们先来建立一个templates文件夹,而后在里面写几个常见的模板文件,这里的模板文件运用到了模板字符串,结构以下:

模板文件

reactClass.js

module.exports = function (className) {
    return `
import * as React from 'react';

export class ${className} extends React.Component{
    constructor(props){
        super(props);

        this.state = {}
    }

    componentDidMount(){

    }

    render() {
        return (
            <div></div>
        )
    }
}
    ` 
}

vueTemplate.js

module.exports = function () {
    return `
    <template>
        <div></div>
    </template>
    <script>
    export default {
        data() {
            return {}
        }
        methods: {

        }
    }
    </sctipt>
    <style lang="scss" scoped>
    
    </style>
    `
}

index.js

const reactClass = require('./reactClass');
const vueTemplate = require('./vueTemplate');

module.exports = [
    { name: 'reactClass', src: reactClass },
    { name: 'vueTemplate', src: vueTemplate }
]

模板文件建立完成后,咱们先把它放在一边,待会儿才用的上。

建立交互命令行以及调用模板

当咱们输入 mycli create file 命令后,须要获得下图中的效果,咱们能够手动上下进行选择,也就是能够被称为交互式的命令。

选择

这里就要用到咱们上文中提到的另一个库——Inquirer.js

首先确定须要进行安装

npm install inquirer

引入并修改咱们根目录下的index.js:

#!/usr/bin/env node

const { program } = require('commander');
const inquirer = require('inquirer');

// 引入模板文件
const templates = require('./templates/index');

// 命令行选择列表
let prompList = [
    {
        type:'list',
        name: 'template',
        message: '请选择你想要生成的模板?',
        choices: templates,
        default: templates[0]
    }
]

...

// 建立文件命令行
program
    .command('create <filename>')
    .description('建立一个文件')
    .action(async (filename) => {
        const res = await inquirer.prompt(prompList)
        console.log(res)
    })

// 处理命令行输入的参数
program.parse(process.argv);

接下来咱们在命令行中输入:

mycli create file

就能够获得上面所展现的效果

选择

而后选择第一个后回车:

选择一

能够看到输出了咱们所选择模板的名字。接下来就是进行实际文件的建立。

建立项目文件

建立文件则须要调用node.js的fs相关api,而后修改index.js:

// 处理文件
const fs = require("fs");

...

// 建立文件命令行
program
    .command('create <filename>')
    .description('建立一个文件')
    .action(async (filename) => {
        const res = await inquirer.prompt(prompList)
        if(res.template === 'reactClass') {
            templates.forEach((item) => {
                if(item.name === 'reactClass') {
                    fs.writeFile(`./${filename}.jsx`, item.src(filename), function(err) {
                        if(err) {
                            console.log('建立失败:', err)
                        } else {
                            console.log(`建立文件成功!${filename}.jsx`);
                        }
                    })
                }
            })
        }
        if(res.template === 'vueTemplate') {
            templates.forEach((item) => {
                if(item.name === 'vueTemplate') {
                    fs.writeFile(`./${filename}.vue`, item.src(), function(err) {
                        if(err) {
                            console.log('建立失败:', err)
                        } else {
                            console.log(`文件建立成功!${filename}`);
                        }
                    })
                }
            })
        } 
    })
    
...

咱们再次在命令行中输入mycli create file,而后选择一个模板。

输出:

建立文件成功!file.jsx

同时咱们能够看见项目根目录下面新增了一个file.jsx文件:

生成文件

打开file.jsx能够看见文件的类名也进行了相应的填写。不只如此,由于咱们的mycli是全局安装的,因此能够说在电脑中任何位置,只要咱们输入 mycli create file ,咱们在当前目录下都能获取到file.jsx文件。也就意味着,咱们在开发一些项目的时候,不用在复制粘贴,删删改改。

直接一行命令就能搞定了~

更多功能

既然能建立文件,那么可否建立文件夹?答案是确定的,只须要继续添加命令就行:

...

// 建立文件夹命令行
program
    .command('create-f <folder>')
    .description('建立一个文件夹')
    .action((folder) => {
        if(fs.existsSync(folder)) {
            console.log('文件夹已存在')
        } else {
            fs.mkdirSync(folder);
            console.log('文件夹建立成功')
        }
    });

...

而后在命令行中输入mycli create-f xxx ,一样能够建立想要命名文件夹。

最后

到此咱们的 mycli 已经能进行建立文件,建立文件夹等等操做了。跟着敲一遍,必定会有收获的。后续咱们能够根据项目的实际状况编写模板文件,自定义想要的命令,进行必要的拓展。这个就留给你们尽情的发挥啦~

有兴趣的小伙伴能够关注个人公众号- 前端车站,新文章会第一时间在公众号发。
相关文章
相关标签/搜索