乐趣区

关于javascript:工作效率upup一起来实现一个NodejsCLI开发工具吧

前言

咱们平时我的项目开发中,常常会有很多相似的代码文件,而咱们在应用的时候也会常常的去复制粘贴。为此我之前也写过一篇文章,探讨过进步开发效率的办法,然而说实话,也并不是很好用。

看现在炽热的前端框架,都有本人的 CLI 工具,例如 Vue CLI,creat-react-app 等等,搭建我的项目非常的不便。所以我也在想,要不也实现一个 CLI 工具,不肯定要和后面几个那样高大上,但只有能进步工作的效率,就值得试一试。

初始化我的项目

首先,咱们要关上 CLI 界面,用 npm 初始化一个我的项目:

npm init

package.json

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

外面一些用不上都曾经去掉。

自定义命令

置信很多小伙伴在应用 npm 初始化我的项目的时候,或者在用 Vue CLI 搭建我的项目的时候,会发现它们有一个共同点——都有本人个性化的命令,感觉有点酷炫。那么咱们怎么能力实现本人的命令呢,很简略,在 package.json 增加 bin

{
  "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 进行批改:

index.js

#!/usr/bin/env node

console.log("执行胜利")

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

设置实现后,就能够 全局 装置咱们的 CLI 工具了:

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.js 和 Inquirer.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 曾经能进行创立文件,创立文件夹等等操作了。跟着敲一遍,肯定会有播种的。后续咱们能够依据我的项目的理论状况编写模板文件,自定义想要的命令,进行必要的拓展。这个就留给大家纵情的施展啦~

有趣味的小伙伴能够关注我的公众号 -前端车站,新文章会第一工夫在公众号发。

退出移动版