#!/usr/bin/env node const program = require('commander') // 定义当前版本 // 定义使用方法 // 定义四个指令 program .version(require('../package').version) .usage('<command> [options]') .command('add', 'add a new template') .command('delete', 'delete a template') .command('list', 'list all the templates') .command('init', 'generate a new project from a template') // 解析命令行参数 program.parse(process.argv)
这个文件的主要作用就是定义指令,现在我们用 node ./bin/xr 运行一下,就能看到如下结果:
当然,你可能会觉得每次输入 node ./bin/xr
这个命令有点麻烦,没关系,我们可以在 package.json 里面写入已下内容:
// bin 用来指定每个命令所对应的可执行文件的位置 "bin": { "xr": "bin/xr" }
然后在根目录下执行 npm link (就是把命令挂载到全局的意思),这样我们每次只要输入 xr,就可以直接运行了,so cool,就像下面这样:
是不是好像有点样子了呢:grin::grin::grin:,那就让我们继续完善下 bin 目录吧!ok,让我们在 bin 目录下再新建四个文件,分别对应上面的四个指令,然后分别处理四个指令要做的事情,如下图:
同样的,我们修改一下 package.json 里面的 bin 内容,如下:
"bin": { "xr": "bin/xr", "xr-add": "bin/xr-add", "xr-delete": "bin/xr-delete", "xr-list": "bin/xr-list", "xr-init": "bin/xr-init" }
然后执行 npm unlink 解绑全局命令,再执行 npm link 重新把命令绑定到全局,就像下面这样:
最后顺便在根目录下新建一个 template.json 文件,里面的内容就是一个 {}。
编写具体指令
好了,一切准备就绪,接下来就让我们来写下具体的四个指令吧。
xr-add
这个内容也是比较少,直接看代码:
#!/usr/bin/env node // 交互式命令行 const inquirer = require('inquirer') // 修改控制台字符串的样式 const chalk = require('chalk') // node 内置文件模块 const fs = require('fs') // 读取根目录下的 template.json const tplObj = require(`${__dirname}/../template`) // 自定义交互式命令行的问题及简单的校验 let question = [ { name: "name", type: 'input', message: "请输入模板名称", validate (val) { if (val === '') { return 'Name is required!' } else if (tplObj[val]) { return 'Template has already existed!' } else { return true } } }, { name: "url", type: 'input', message: "请输入模板地址", validate (val) { if (val === '') return 'The url is required!' return true } } ] inquirer .prompt(question).then(answers => { // answers 就是用户输入的内容,是个对象 let { name, url } = answers; // 过滤 unicode 字符 tplObj[name] = url.replace(/[\u0000-\u0019]/g, '') // 把模板信息写入 template.json 文件中 fs.writeFile(`${__dirname}/../template.json`, JSON.stringify(tplObj), 'utf-8', err => { if (err) console.log(err) console.log('\n') console.log(chalk.green('Added successfully!\n')) console.log(chalk.grey('The latest template list is: \n')) console.log(tplObj) console.log('\n') }) })
这个文件主要目的就是添加模板并存储起来,上面的注释应该都写的挺清楚了。我们执行 xr add 来看看效果:
这里的模板名称(自己随便取)相当于 vue init webpack project-name 当中的 webpack
;模板地址要注意一下,像下面这样写就可以,这里以 github 为例:
xr-delete
如果你理解了上面的那个步骤,这步对你来说应该也是洒洒水啦!上代码:
#!/usr/bin/env node const inquirer = require('inquirer') const chalk = require('chalk') const fs = require('fs') const tplObj = require(`${__dirname}/../template`) let question = [ { name: "name", message: "请输入要删除的模板名称", validate (val) { if (val === '') { return 'Name is required!' } else if (!tplObj[val]) { return 'Template does not exist!' } else { return true } } } ] inquirer .prompt(question).then(answers => { let { name } = answers; delete tplObj[name] // 更新 template.json 文件 fs.writeFile(`${__dirname}/../template.json`, JSON.stringify(tplObj), 'utf-8', err => { if (err) console.log(err) console.log('\n') console.log(chalk.green('Deleted successfully!\n')) console.log(chalk.grey('The latest template list is: \n')) console.log(tplObj) console.log('\n') }) })
应该很好理解,就不过多解释了,我们直接执行 xr delete 看下效果:
xr-list
这个更简单了,两行代码搞定:
#!/usr/bin/env node const tplObj = require(`${__dirname}/../template`) console.log(tplObj)
是不是简单到爆:boom:。我们执行 xr list 看看效果:
因为刚才一添加一删除,所以目前没有模板,就输出 {}。
xr-init