本篇文章给大家介绍一下Nodejs和命令行程序。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。
造物无言却有情,每于寒尽觉春生。千红万紫安排著,只待新雷第一声。 —— 清.张维屏 《新雷》
植根于Unix系统环境下的程序,很多都把贯彻Unix系统设计的哲学作为一种追求。Unix系统管道机制的发明者Douglas McIlroy把Unix哲学总结为三点:
专注做一件事,并做到极致。
程序协同工作。
面向通用接口,如文本数据流。
随着Unix/Linux系统在服务器上影响力越发强大,以及各种跨平台解决方案的发展,这种哲学也被带到了各种平台上。若干年前,笔者第一次接触NodeJS和其包管理解决方案NPM时候,就感觉到其官方倡导的风格,和Unix系统哲学非常契合。近年来,随着NodeJS在服务端以及前端构建领域上的不断开拓,NodeJS的这种思想也正快速的渗透到这些领域。
其实,NodeJS的本身,也是开发命令行程序的一个重要利器。本文就将介绍几个常用的NodeJS相关命令行程序,之后介绍几个开发命令行中常用的组件,最后介绍发布npm包以及带scope的包的发布方法。
【推荐学习:《nodejs 教程》】
命令行,可以简单定义为是一种基于文本流的用户交互接口和交互方式。命令行程序常常通过命令行参数的传递来得到不同的运行方式。而由于一切命令的下达,都是基于文本的,所以也为元编程,提供了便利。
命令行程序可以是编译执行的,也可以是解释执行的。对于编译后的命令行程序,将直接以机器码执行。而对于大多数的解释型的命令行程序,运行往往需要借助命令行解释程序。
这篇文章中提到的命令行程序特指需要解释程序的命令行程序。
可以充当命令行解释程序的,其实包含了大家听说过的常见的解释器,比如bash、zsh、perl、python、ruby、tcl等等,当然还有NodeJS。
打开一个命令行程序,比较标准的写法是在第一行写明解释程序的路径,如:
#!/usr/local/opt/python/bin/python3.6
这里 #!
成为shebang,一般位于文件的最开头。在Unix系统中,#!
所在行后面的部分将被视为解释器指令。同时会把文件所在路径作为参数附在解释器后面。上例中,如果文件是/usr/local/bin/pip
,则直接运行/usr/local/bin/pip
的效果,等同于/usr/local/opt/python/bin/python3.6 /usr/local/bin/pip
。
这样做,使得用户无需关心解释程序,无需关心代码编写的语言,直接运行对应的命令行程序本身就好了。这也是shebang存在的意义。不过,由于系统设定的原因,使用windows的同学可能无法享受这种便利,一般还需手动指定解释程序的路径。但是,他们可以双击运行:-)。
可以试着用文本编辑工具打开一个NodeJS写成的脚本如:webpack
,会发现其第一行是#!/usr/bin/env node
。这句话并不是直接的NodeJS的解析程序。这里, /usr/bin/env
是一个程序,目的是从系统的PATH中寻找对应名字的解释程序的地址。此时,解释程序可以被安装在各种路径,只要在系统PATH中注册过,就可以找到了。
可能大家遇到过这种问题,在运行某些NodeJS程序会出现报错:
/usr/bin/env: node: No such file or directory
此时可以从系统PATH中是否有node这个文件路径、某些版本的NodeJS是否名为node等方向来排查问题。
在NodeJS目前已经成为前端工作流的主力语言的情况下, babel
和webpack
基本已经成为前端开发、测试、发布上的重要工具。同时围绕babel
和webpack
有一系列周边的工具包和插件协助开发者完成日常开发的方方面面。
同時,目前最受歡迎的前端框架Angular、react、vue(以首字母為序),各自有自帶的鷹架和開發輔助工具。如ng-cli
、create-react-app
和vue-cli
等等。更有Poi這樣的通吃React和Vue的鷹架工具。
上面這部分每一個都可以獨立出來單獨講解。有興趣的讀者可以參考上述工具的官方網站來獲取更多資訊。
下面來說幾個其他方面的NodeJS相關的軟體包。
大多數情況,我們只需面對單一的NodeJS版本。等到時機成熟,再統一把NodeJS版本升級到更高版本。
不過筆者就曾經遇過一個年久失修失修的專案需要重新維護的情況。此時需要把NodeJS版本切到舊版。同時,我們也不想捨棄大多數專案運行的新版本NodeJS環境。
這種情況可以使用n或nvm。下圖展示了,用n下載並切換到一個新版本的過程。
除了下載之外,n還提供了清單的方式切換多個版本,以及刪除某個版本的方法。讀者可以在安裝之後使用n -h
查看所有可用參數。
n採用bash編寫。但提供了一個npm倉庫安裝的入口,可以使用大家傳統意義的npm安裝法進行全域安裝,前提是你必須要有一個可以運作的NodeJS環境。
npm install -g n
或是在沒有NodeJS的環境下,可以使用n-install
腳本。安裝只需運行:curl -L https://git.io/n-install | bash
。
如果是windows用戶,在windows10下面可以安裝wsl
來獲得Linux腳本運行環境,官方倉庫的一個issues,對此有一個操作說明。
對windows10以下的用戶,可以考慮折騰下Cygwin
。
除了n之外,還有一個管理工具為nvm,也是採用bash腳本編寫。安裝亦可使用安裝腳本來完成。如:curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
或wget -qO- https://raw.githubusercontent .com/creationix/nvm/v0.34.0/install.sh | bash
。這裡的v0.34.0
是版本號,可能會隨著版本迭代而改變。
使用windows的讀者,除了上述wsl
和Cygwin
之外,可以考慮使用nvm-windows這個用Golang寫的版本。
就目前的最新版本來說,n和nvm的都會嘗試處理公共的依賴函式庫,然而處理方式是不一樣的。
n和nvm都會在首次使用某個版本時將此版本的NodeJS下載至本地,不同的是:n將嘗試用新版本代替系統路徑中,關鍵路徑如bin、lib、include、 share的包。 nvm則是保留每一個版本的副本,並將NodeJS的系統路徑指向.nvm維護的沙箱位址。
從處理上,nvm看起來更輕量級和高效,但是需要修改系統的PATH,這一步nvm腳本會自動完成。 n則無需入侵系統路徑,但每次修改時均需作業系統路徑,且此時最好使用sudo n
運行,避免因權限不足,拒絕向系統路徑複製。
由於nvm會修改PATH位址,所以如果同時預設安裝nvm和n,n會運作不正常。一個方案是避免同時安裝,另外可以手動修改PATH,讓預設的NodeJS路徑先於nvm的系統路徑,如修改PATH片段為:
/usr/local/bin:/Users /leon/.nvm/versions/node/v10.6.0/bin:
nodemon是執行器,意義在於,如果版本變化或程式變化,則無需重新啟動。這在開發時候非常有用。
nodemon還可以指定運行的端口,如:
nodemon ./server.js localhost 8080
nodemon --exec "python -v" ./app.py,將監控app.py的內容,並在最開始以及發生變化時候,呼叫
python -v進行解析。當然,如果你的app.py指定了shebang,也可以不需指定解析函數。
nodemon.json,也可以在package.json中透過
nodemonConfig欄位指明。
这里是官方提供的一份配置文件的样例,供读者参考。
再来说说npx。什么是npx呢?简单说,就是找到并运行一个包,并且“用完即走”。
这里有两层意思:
找到。从哪里找:先是当前的依赖,然后是PATH,还找不到就到网上找来安装。
用完即走。即使从网上安装的,运行完就会删掉,不会留下运行的包。 读者可以试着运行下:npx github:piuccio/cowsay "awesome npx"
体验下。
这实在是居家旅行、开发调试的利器。比如我要在当前目录下开一个http服务,可以直接运行:npx http-server
之后就可以直接在浏览器访问这个地址进行调试了。
另外,如果你需要临时用一个老版本的node来运行某个脚本,也可以祭出npx,这个node会被临时安装、临时使用、用完即走。
npx -p node@6 npm init
nrm/yrm维护了一个列表,包括npm主站和其他镜像。可以使用nrm/yrm use 快速切换,以达到最快的下载速度。nrm维护的是npm的注册表,yrm维护的是yarn注册表。
除了直接用大神们写好的命令之外,我们也可以按照自己的需求定制自己需要的NodeJS包。我们知道,命令行其实也是一种人机交互,因此,交互上有很多可以借鉴的效果。编写者只需将包倒入就可以使用这些交互效果。这里笔者给大家推荐几个包
命令行的一个特点就是根据参数的不同调整运行策略。然而处理命令行输入以及验证是一个非常繁琐的事情。为此,TJ大神曾经创立了commander包。最基础的用法如下:
var program = require('commander'); program .version('0.1.0') .option('-p, --peppers', 'Add peppers') .option('-P, --pineapple', 'Add pineapple') .option('-b, --bbq-sauce', 'Add bbq sauce') .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble') .parse(process.argv); console.log('you ordered a pizza with:'); if (program.peppers) console.log(' - peppers'); if (program.pineapple) console.log(' - pineapple'); if (program.bbqSauce) console.log(' - bbq'); console.log(' - %s cheese', program.cheese);
默认地,commander会自动创建-h的帮助文件,即利用每一个option的输入产生帮助文案。
用户的每一个输入,都会放置在program对应option长名的字段的驼峰形式上,如果没有提供长名,则放在短名字段上。上例中,如使用: testcommander -p 111 -P 222 -b 333
则依次存储在program
的peppers
、pineapple
和bbqSauce
上。
同时,commander提供多种验证方式,如正则表达式:
program.option('-s --size <size>', 'Pizza size', /^(large|medium|small)$/i, 'medium')</size>
则指定只能输入特定的值。
同时,commander提供一个方案,允许用户设置子命令。commander称之为Git风格的子命令。
var program = require('commander'); program .version('0.1.0') .command('install [name]', 'install one or more packages') .command('search [query]', 'search with optional query') .command('list', 'list packages installed', {isDefault: true}) .parse(process.argv);
这个例子中,假设命令行名字为pm
,则当用户输入pm-install
、pm-search
或pm-list
时候,commander会尝试在入口文件的同一级目录找到install
、search
或list
,并交给这个文件去执行。
在编写web程序时候,大家经常会展示一个进度条。用以缓解用户在等待时候的焦虑。其实在命令行程序中也会有这种交互方式。比如wget就会在下载过程中给出进度提示。
在NodeJS中也有这样的效果可以使用。这就是progress包。下面的代码,运行结果是下载CentOS安装盘。在下载之中,会实时打印进度
const ProgressBar = require("progress") const request = require("request") const progress = require("request-progress") const fs = require("fs") const download = (url, headers, target, totalSize) => { let percent = 0 const bar = new ProgressBar('下载中: ├:bar┤ 完成:percent 预估完成时间:eta秒 用时:elapseds', { total: 100, complete: "█", incomplete: "─", width: 60 }) let opt = { headers, url: url } return new Promise((resolve, reject) => { progress(request.get(opt)) .on('progress', function (state) { let progressFix = ((state.percent) * 100).toFixed(2) delta = progressFix - percent bar.tick(delta) percent = progressFix }) .on("error", () => { return reject() }) .on('end', () => { bar.tick(100 - percent) console.log('\n') return resolve(target) }) .pipe(fs.createWriteStream(target)); }) } const foo = { getHeaders: () => { const headers = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Charset': 'UTF-8,*;q=0.5', 'Accept-Encoding': 'gzip,deflate,sdch', 'Accept-Language': 'en-US,en;q=0.8', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:13.0) Gecko/20100101 Firefox/13.0' } return Object.assign({}, headers) }, download: function (url, target, totalSize){ let headers = this.getHeaders() headers = Object.assign(headers) download(url, headers, target, totalSize) } } foo.download("http://mirrors.cmich.edu/centos/7.6.1810/isos/x86_64/CentOS-7-x86_64-DVD-1810.iso", "CentOS-7-x86_64-DVD-1810.iso", 4508876.8 )
运行的结果如图:
这个包的核心就是根据内置和自定义的token在命令行打印出相应的字符,用以完成交互。
chalk是一个命令行交互的着色工具。在命令行支持的情况下,可以支持最多16位色域(前提是命令行终端可以支持)。一般可以配合console.log使用,如:
const chalk = require('chalk'); const log = console.log; // Combine styled and normal strings log(chalk.blue('Hello') + ' World' + chalk.red('!'));
笔者曾经做过一个在命令行下显示图片的程序,就是利用的chalk和console.log进行的配合。
在需要不断的同用户进行交互式问答,并根据用户的输入进行验证和路径选择,这个时候inquirer是非常趁手的工具。它内置了单选、多选、问答等多种交互方式。大家可以感受下:
甚至可以通过插件实现suggest
vue框架的脚手架vue-cli是一个使用inquire的绝佳案例,读者可以通过阅读源码,感受下大神出神入化的使用。
ora打印出一个优雅的文本小图标,用于在各种情况下给出用户优雅而清晰的提示。用法很简单:
const ora = require('ora'); const spinner = ora('Loading unicorns').start(); setTimeout(() => { spinner.color = 'yellow'; spinner.text = 'Loading rainbows'; }, 1000);
puppeteer是谷歌开发的无头浏览器,使得命令行亦可操作浏览器,并能根据浏览器的执行结果进行进一步操控。因为puppeteer源自官方,所以之前类似项目PhantomJS的开发者决定不再更新PhantomJS。
目前puppeteer已经广泛用于前端测试,端对端测试,以及爬虫。
鉴于篇幅无法展开介绍,读者可以参考其官方文档。同时,奇舞周刊中黄小璐老师的的这篇文章以及李光钊老师的这篇文章都曾经介绍过puppeteer的使用。
写好的NodeJS包需要发布出去,才能给大家使用。npm publish
就是为了这个需求而产生的。为了发布你需要在npm上注册用户,并登录,然后发布就好了。npm的详情页面以及各个镜像会在一段时间内自动更新。
如果你的NodeJS包,是使用尚未广泛支持的语法写成的。那么需要在package.json的script
字段加入prepublish
命令,调用babel等预编译器处理,使得程序可以有更多的兼容性。
对于希望用户在全局使用的命令,要注意在根目录写好入口,一般是在package.json中的bin字段,指定入口文件。在安装时,如果是全局安装,npm将会使用符号链接把这些文件链接到prefix/bin,如果是本地安装,会链接到./node_modules/.bin/。
除了通常的包,还有一种是带有scope的包,vue-cli的3.0版本就是@vue开头的。这个scope是组织的名字。每一个带有scope的包有公有和私有之分,私有的需要付费给npm。
目前npm的读写权限策略如下:
如果是个人,可以考虑增加公有的命名空间。如果是企业付费用户,你在发布相关包之前,需要申请成为这个scope的member。
对公有scope,首先将包的name改为@scope名字/包名
,同时,在发布时,使用npm publish --access public
即可。
本文简述了命令行的意义和优势,介绍了解释型命令行的运行机制,同时介绍了几个NodeJS相关的命令行工具,推荐了几款撰写命令行程序常用的包,最后,概述了发布包和使用scope的发布情况。希望给大家的NodeJS命令行相关开发和技术选型,提供一些有用的帮助。
原文地址:https://juejin.cn/post/6844903821672448008
作者:刘观宇
更多编程相关知识,请访问:编程视频!!
以上是一起了解Nodejs和命令列程式的詳細內容。更多資訊請關注PHP中文網其他相關文章!