一统江湖的大前端(6)commander.js + inquirer.js——懒,才是第一生产力
《一统江湖的大前端》系列是自己的前端学习笔记,旨在介绍javascript在非网页开发领域的应用案例和发现各类好玩的js库,不定期更新。如果你对前端的理解还是写写页面绑绑事件,那你真的是有点out了,前端能做的事情已经太多了,
手机app开发
,桌面应用开发
,用于神经网络人工智能的库
,页面游戏
,数据可视化
, 甚至嵌入式开发
,什么火就搞什么,活脱脱一个蹭热点小能手。如果你也觉得前端的日常开发有些枯燥,不妨一起来看看前端的另一番模样。
一.[懒]——才是第一生产力
你没有看错,懒绝壁是第一生产力,技术的进步,很多时候都是因为一些非常聪明的人难以忍受一些(在他们眼里)枯燥重复且低效的东西,从而发明出的东西,无论这些新发明在经历了迭代和打磨之后看起来多么牛逼耀眼,但其本质基本都可以归纳为:
是聪明的懒人搞出的可以让自己更省事的东西。
- jquery的流行,是因为开发者懒得为dom编写跨浏览器兼容性代码
- angular.js的流行, 是因为开发者连dom都懒得操作
- bootstrap的流行, 是因为开发者懒得编写自适应样式
- webpack的流行, 是因为开发者懒得做一系列上线前的准备工作
......
有的人越懒越牛逼,有的人越懒越逗逼,看来懒也是个技术活,懒出高度,懒出艺术,那才是真的高端懒。
二.从gui到cli
gui
(grapic user interface,即图形化用户界面)和cli
(command line interface,即命令行交互界面)都有其拥护者。
大家都懒,只是对懒的认知不同,用gui
的人懒得去记命令,用cli
的人懒得去挪鼠标。
很多前端童鞋都通过可视化工具小乌龟
来管理git
代码仓库,可视化工具的好处在于可以让初学者可以更直观更容易地去管理代码。
但是笔者发现很多熟练的开发者都更喜欢使用命令行工具(以下简称cli工具),不仅因为cli工具可以满足装x需求,更是因为它可以帮你省掉很多繁琐的移动鼠标和点击的动作。
有时候你并不需要去记忆很多指令和参数(当然用的次数多了,你不想记也记住了),几乎所有的命令行工具只要简单滴使用-h
或--help
参数就可以打印出帮助文件,你完全可以边学边用,逐步熟悉。
很多熟悉vue
的同学都使用过vue-cli
命令行工具来初始化一个vue项目,如下图所示,通过向导式问答收集关键参数信息,然后自动生成相应的工程文件,比你自己各种新建文件和新建文件夹效率高多了。
接下来,请跟随笔者一起,看看一个前端开发人员如何从零开始打造一款属于自己的cli
工具吧~
三.相关知识储备
1.前提条件
你需要一些node.js的api知识和一些基本的命令行使用经验。详细的文档可以访问nodejs官方api获取更多信息。
2.readlinereadline
工具包用于逐行处理信息,常用的api包括:
-
createinterface
用于创建接口实例,成功调用后返回一个接口实例,调用后使用方法如下:
var rl = readline.createinterface({ input: process.stdin, output: process.stdout });
-
rl.question(query, callback)
实例方法,提供一个问答式单行交互方法,向用户展示提示信息,然后接受并处理用户输入,调用方法如下:
rl.question('你学会怎么用了吗?',function(input){ console.log('你输入了:',input); })
-
rl.write(info)
实例方法,向创建rl接口实例时连接的output输出流输出信息,通常使用主进程输出流process.stdout
,调用方法如下:
rl.write('我是这样用的');
做个demo轻松一下(demo的源码请在附件拿):
3.child_process
child_process包提供了利用子进程执行命令或调用文件的能力,常用的api包括:
-
child_process.spawn()
实际执行方法,其他方法均为基于此方法的封装,使用方式如下:
const { spawn } = require('child_process'); const ls = spawn('ls', ['-lh', '/usr']); ls.stdout.on('data', (data) => { console.log(`stdout: ${data}`); }); ls.stderr.on('data', (data) => { console.log(`stderr: ${data}`); }); ls.on('close', (code) => { console.log(`child process exited with code ${code}`); });
-
child_process.exec(), child_process.execfile()及同名的同步方法
均是对spawn
方法一定程度上的封装,使用更方便。
再来个demo轻松一下,通过在windows命令行工具中执行js文件,执行了dir
命令(demo的源码请在附件拿):
ps:乱码的问题涉及到子进程和主进程通讯时的信息的编码和解码问题,遇到实际问题的童鞋可以了解一下iconv-lite
这个插件.
四.guide风格命令行开发工具——inquirer.js
github地址为:inquirer.js地址
guide风格的命令行,指提问-回答模式的命令行,inquirer.js
支持常见的input输入
,单选
,多选
,是/否
等常见提问类型,并暴露了增加自定义类型的接口,参考官方文档很容易使用。
api使用举例:
const questions = []; inquirer .prompt( /* pass your questions in here */ [{ type: 'confirm', name: 'tobedelivered', message: 'is this for delivery?', default: false }] ) .then(answers => { // use user feedback for... whatever!! });
来看看官方提供的一个pizza订购工具pizza.js
的效果(是不是有vue-cli的既视感~~~):
五.git风格命令行开发工具——commander.js
github地址为:commander.js地址
git风格命令行,是指通过主指令+子指令+参数的模式运行命令实现功能,和guide风格命令行没有本质区别,只是使用习惯的偏好。
api使用举例:
program .version('0.0.1') .description('an application for pizzas ordering') .option('-p, --peppers', 'add peppers') .option('-p, --pineapple', 'add pineapple') .option('-b, --bbq', 'add bbq sauce') .option('-c, --cheese <type>', 'add the specified type of cheese [marble]') .option('-c, --no-cheese', 'you do not want any cheese') .parse(process.argv);
来看看官方提供的这个pizza订购工具pizza.js
的效果(老外是有多喜欢吃pizza!!!):
六.不同风格的实现思路
1.基本架构
-
web版本
- 前端使用任意框架制作,点击某功能按钮时,向后端发送带参请求
- 后端为node服务器,监听指定端口,接收到客户端请求后,调用具体功能
- 根据后端执行情况信息在前端展示的实时性要求,选择长连接或普通连接
- 后端使用
child_process
或相关类库实现命令并将信息传输至前端
-
guide风格命令行
- 直接使用
inquirer.js
库编写问题组或分支问题树 -
inquirer.js
最终将用户输入绑定在一个对象上 - 使用
inquirer.js
收集到的参数 - 带参数运行命令或脚本
- 直接使用
-
git风格命令行
- 直接使用
commander.js
库的api编写支持的指令 -
commander.js
会从注册的命令及子命令中寻找匹配 - 使用
commander.js
收集到的参数运行对应的命令或脚本
- 直接使用
2.其他问题
- 兼容性
- 使用多种脚本格式
为了兼容不同运行环境,可以为实际需要执行的命令准备.bat
和.sh
两套脚本,在node.js代码中根据process.platform
查询当前系统环境并调用对应格式的脚本 - 使用兼容性插件库
例如《一统江湖的大前端(4)——shell.js》中提及的shell.js
库,可将自动化脚本重构为js版本代码,实现跨平台运行。
- 使用多种脚本格式
- 全局执行命令
- 开发版本
开发版本的程序,可以在代码根目录中使用npm link
将其注册为全局安装,当开发完毕正式发布后,使用npm unlink
去除连接即可。 - 发布版本
当node包开发完成并使用publish
命令正式发布以后,即可通过npm install -g xxx
或yarn global add xxx
直接从npm上下载并全局安装,然后即可全局使用。
- 开发版本
七.要什么demo?直接搞实战!
接下来我们在windows环境下实现一个自动化脚本,实现的功能主要包括:
- 1.删除旧目录
- 2.新建目录
- 3.从远程git仓库指定分支下载代码
- 4.在本地建立新分支并
auto_download.js源码:
var child_process = require('child_process'); function exectask(issuenumber, openlocalhost) { //示例中的自定义配置信息从configjson对象中获取 var origindir = configjson['项目信息']['远程仓库地址']; var originbranch = configjson['feature分支']['远程分支名称']; var destdir = configjson['项目信息']['本地仓库地址']; var projectname = configjson['项目信息']['项目名称'] + '_issue'; var devbranch = configjson['本地开发']['默认分支前缀'] + issuenumber; //执行下载脚本 var issue_process = child_process.spawn('download_dev_branch.bat', [destdir, projectname, origindir, originbranch, devbranch], { stdio : 'inherit' }); //监听标准输出 issue_process.stdout .on('exit', function (number) { console.log(number); console.log('感谢您使用dash-toolbox!') }); } exectask(12315, true);
自动化脚本download_dev_branch.bat
源码:
@echo off rem 当前脚本用于将远程仓库的开发分支代码下载至指定的本地目录并生成开发分支 rem %1 - 本地仓库文件夹 rem %2 - 本地指定分支文件夹名 rem %3 - 远程仓库地址 rem %4 - 远程开发分支名 rem %5 - 包含issue代码的本地分支 @echo on cd %1 rmdir /s/q %2 mkdir %2 && cd %2 git init git remote add origin %3 git fetch origin %4 :%5 --progress --no-tags git checkout %5 exit(0)
使用方法:
在文件目录下开启命令行cmd.exe
,输入node auto_download
即可看到在对应的目录下载了代码:
自动化脚本的部分也可以采用
node
的file api
来实现。
八.后记
在学习了以上知识后,笔者决定开发一款命令行工具——dash-toolbox
。
其目的主要是:
在保密性要求较高所以不通外网的环境下,将常用的文档资源集中化,将常规的动作自动化。
在全局环境下命令行中输入dash
即可启动guide模式,输入dash -h
类似命令即可支持git模式,并已经制作了web模式的首页。来先睹为快感受一下:
其实是受够了一次次花20秒钟改代码,然后花20分钟提交代码和发布的过程,尽管代码提交后的流程已经打通了jenkins的自动化流程,但代码提交前的本地工作仍然是手动的,我真的只是懒而已。