咱們平時項目開發中,常常會有不少相似的代碼文件,而咱們在使用的時候也會常常的去複製粘貼。爲此我以前也寫過一篇文章,探討過提升開發效率的方法,可是說實話,也並非很好用。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 添加 bin
:git
{ "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 init
、 npm install -g
,其中包含一些交互式的,好比在初始化項目時, npm init
提供一些輸入問答形式的命令。接下來,咱們就來爲本身的CLI工具添加這些相似的命令。
咱們能夠依賴兩個庫進行咱們的開發:commander.js和Inquirer.js
這兩個庫的具體用法,這裏就過多的介紹,小夥伴們能夠點擊上面名字的連接去熟悉一下,花不了太多時間,實際用起來也不難,後面那個沒有中文Readme,可是不妨礙你們會搜索呀~對不對。
咱們首先來實現相似於 npm -v
、node -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 已經能進行建立文件,建立文件夾等等操做了。跟着敲一遍,必定會有收穫的。後續咱們能夠根據項目的實際狀況編寫模板文件,自定義想要的命令,進行必要的拓展。這個就留給你們盡情的發揮啦~
有興趣的小夥伴能夠關注個人公衆號- 前端車站,新文章會第一時間在公衆號發。