前言
之前一篇文章介绍了 Node.js 的三个模块的基础 API,面对文档时不那么抓瞎,基础 API 用习惯了也差不多找到感觉,之后想用啥就可以自己照着文档找就好了。
除了 Node 提供的基础模块之外,我们在开发中必不可少地会用到第三方模块,也就是我们最常见的社区 NPM 包。这篇文章主要就是介绍一些在开发 Node 的时候,常用的一些基础工具包。
两篇文章配合使用,应该可以帮助你上手 Node 开发。
文件系统
这些工具包的功能就是在 Node 本身的 fs
模块基础上提供更加方便的文件系统操作 API。
glob
一句话介绍
glob
是一种文件匹配模式,起源于 Unix
,比如我们常见 *.js
匹配所有 js
文件就是使用了 glob
模式。
GitHub 地址:https://github.com/isaacs/node-glob[1]
使用方法
glob(pattern, [options], callback)
,glob
方法接收三个参数:
- callback: 回调函数
(error, files) => {}
其中 options
是可选项:文档[2],可以不传,直接将回调函数放在第二个参数。
如果不想使用回调的方式,可以使用同步方法 glob.sync(pattern, options)
,用法一致,返回值即是匹配文件数组。
举例
当前文件目录如下:
.
├── a
│ ├── a.css
│ ├── a.js
├── .eslintrc.js
│ └── b
│ ├── b.css
│ └── b.js
├── index.js
├── package.json
index.js 代码如下:
const glob = require("glob")
glob("a/**/*.js", (error, matches) => {
if (!error) {
console.log(matches);
}
});
try {
const files = glob.sync("a/**/*.js");
console.log(files);
} catch (e) {}
输出如下:
[ 'a/a.js', 'a/b/b.js' ]
是不是发现 .eslintrc.js
文件并没有被匹配到。默认情况下,glob
不会匹配以 .
开头的文件,需要我们在配置项中打开:
const glob = require("glob")
glob("a/**/*.js", { dot: true }, (error, matches) => {
if (!error) {
console.log(matches);
}
});
// [ 'a/.eslintrc.js', 'a/a.js', 'a/b/b.js' ]
globby
一句话介绍
globby
是增强型的 glob
,提供了 Promise
的封装。最终要的是它支持多模式匹配,相比于 glob
只能传入一个 pattern
字符串,globby
支持传入一个 pattern
数组。
GitHub 地址:https://github.com/sindresorhus/globby[3]
使用方法
globby(patterns, options?)
,globby
接收两个参数,返回 Promise
:
举例
当前文件目录如下:
.
├── a
│ ├── a.css
│ ├── a.js
├── .eslintrc.js
│ └── b
│ ├── b.css
│ └── b.js
├── index.js
├── package.json
index.js 代码如下:
const globby = require('globby');
(async () => {
const files = await globby(['a/**/*.js', 'a/**/*.css'], { dot: true });
console.log(files);
})();
输出如下:
[ 'a/.eslintrc.js', 'a/a.js', 'a/b/b.js', 'a/a.css', 'a/b/b.css' ]
fs-extra
一句话介绍
Node 内置了 fs
模块供开发者和文件系统交互,但是用过的同学都知道,它的能力还是挺有限的。所以,在 fs
的基础上,社区提供了 fs-extra
工具包增强文件系统交互,并且提供了 Promise
的调用方式。
GitHub 地址:https://github.com/jprichardson/node-fs-extra[4]
举例
这里介绍几个最常见的:
const fse = require('fs-extra');
(async () => {
// 确认目录是否存在,如果不存在会创建目录
await fse.ensureDir('./a');
// 复制文件
await fse.copy('./a/a.js', './a/aa.js');
// 读 JSON 文件
const aJSON = await fse.readJSON('./a/a.json');
console.log(typeof aJSON, aJSON);
// 写 JSON 文件
await fse.writeJSON('./a/aa.json', { a: 1 }, { spaces: 2 });
// 写 JSON 文件,如果目录不存在会创建
await fse.outputJson('./c/aa.json', { a: 1 }, { spaces: 2 });
// 删文件
await fse.remove('./a/aa.json');
})();
执行命令
这几个 NPM 包的功能主要就是会用于执行一些系统命令,比如 npm install
、git clone
等等。
shelljs
一句话介绍
这个包的作用就和它的名字一样,用 js
来实现 shell
命令。
GitHub 地址:https://github.com/shelljs/shelljs[5]
使用方法
可以通过 shelljs
提供的 exec
命令同步地执行任意的 shell
命令,返回值中的 code
标识是否成功执行,比如:
const shell = require('shelljs');
if (shell.exec('git init .').code === 0) {
console.log('Git 初始化成功');
}
除了 exec
之外,shelljs
也提供了一些常用 shell
命令的包装,比如 which
、echo
等,比如:
const shell = require('shelljs');
shell.echo('Hello Shelljs');
举例
来看两个 shelljs
的常见用法。
const shell = require('shelljs');
// 判断是否有相关开发环境
function hasGitNpm() {
if (!shell.which('git')) {
console.log('Sorry, this script requires git');
shell.exit(1);
}
if (!shell.which('npm')) {
console.log('Sorry, this script requires npm');
shell.exit(1);
}
}
hasGitNpm();
// 安装 npm 包
function installPkg(pkg, type) {
const npm = shell.which('npm');
if (!npm) {
console.log('请先安装 npm');
return;
}
const { code } = shell.exec(
`${npm.stdout} install ${pkg} ${type || '--save'}`
);
if (code) {
console.log(`安装 ${pkg} 失败,请手动安装`);
}
}
installPkg('lodash');
cross-spawn
一句话介绍
在 Node 中,可以通过 child_process
模块来创建子进程,并且通过 child_process.spawn
方法来使用指定的命令行参数创建新进程,执行完之后返回执行结果。而 cross-spawn
包就是提供了关于 spawn
函数的跨平台写法,不用开发者处理跨平台的逻辑。
GitHub 地址:https://github.com/moxystudio/node-cross-spawn[6]
使用方法
用法和 child_process.spawn(command[, args][, options])
保持一致:
const spawn = require('cross-spawn');
const child = spawn('npm', ['install'], { stdio: 'inherit' });
举例
看一个比较常见的 cross-spawn
用法:
const spawn = require('cross-spawn');
// 安装全部依赖
spawn.sync('npm', ['install'], { stdio: 'inherit' });
// 安装指定依赖
spawn.sync('npm', ['install', 'lodash', '--save'], { stdio: 'inherit' });
rimraf
一句话介绍
相当于在命令行中执行了 rm -rf
,咳咳,是不是有点危险啊。
GitHub 地址:hhttps://github.com/isaacs/rimraf[7]
使用方法
rimraf(f, [opts], callback)
,rimraf
方法接收三个参数:
当然,也可以使用 rimraf.sync
同步方法。
const rimraf = require('rimraf');
rimraf('./a/aa.js', error => {
if (!error) {
console.log('删除成功');
}
});
除了在 Node 中用,在 package.json
的 scripts
中也会经常看到这个工具,比如:
{
"scripts": {
"build": "rimraf build && npm run build"
}
}
网络请求
这里主要列了两个目前正在用的网络请求的包。
node-fetch
一句话介绍
相当于在 Node 上使用 Fetch。
GitHub 地址:https://github.com/node-fetch/node-fetch[8]
使用方法
就举个简单例子,其它的看文档就好了:
const fetch = require('node-fetch');
const response = await fetch('https://api.github.com/users/github');
const data = await response.json();
console.log(data);
axios
一句话介绍
axios
就不用介绍了,写前端的同学都知道,用起来也很方便。
GitHub 地址:https://github.com/axios/axios[9]
使用方法
const axios = require('axios');
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
小工具
这里就列一堆用得上的小工具吧,按需用。
open
一句话介绍
open
包可以让你在代码中打开网页、图片等等。比如你经常 npm start
启动项目的时候,是不是会自动唤起浏览器打开一个 localhost
的页面,就是通过 open
包实现的。
GitHub 地址:https://github.com/sindresorhus/open[10]
使用方法
const open = require('open');
await open('http://localhost:8080');
http-server
一句话介绍
http-server
包一般安装在全局使用,可以在本地任意目录 0 配置启动一个 HTTP 服务,一般在本地开发和测试的时候会经常用到。比如,使用 npm build
打包构建出构建产物之后,可以本地执行 http-server build
启动一个服务。
GitHub 地址:https://github.com/http-party/http-server[11]
path-to-regexp
一句话介绍
顾名思义,path-to-regexp
是将指定 path
转换成一个正则表达式的工具,一般在接口路径匹配的时候会用到。
GitHub 地址:https://github.com/pillarjs/path-to-regexp[12]
使用方法
比如我们的 API 的路径有很多,其中有一部分是对外开放的 API,它的路径是 /openapi/*
的,可以这样匹配:
const { pathToRegexp } = require('path-to-regexp');
console.log(pathToRegexp('/openapi/:key'));
输出结果为:
/^\/openapi(?:\/([^\/#\?]+?))[\/#\?]?$/i
url-join
一句话介绍
用 url-join
包可以非常方便地操作一个 url,拼接任意参数。
GitHub 地址:https://github.com/jfromaniello/url-join[13]
使用方法
假设我们需要动态地拼接参数,可以这样:
const urlJoin = require('url-join');
console.log(urlJoin('http://www.google.com', 'a', '/b/cd', '?foo=123'));
输出结果为:
http://www.google.com/a/b/cd?foo=123
semver
一句话介绍
NPM
的 semver
规范相关的工具包,判断版本啥的。
GitHub 地址:https://github.com/npm/node-semver[14]
使用方法
const semver = require('semver')
// 判断是否符合规范
semver.valid('1.2.3') // '1.2.3'
semver.valid('a.b.c') // null
// 判断 a 版本是否比 b 版本高
semver.gt('1.2.3', '9.8.7') // false
// 判断 a 版本是否比 b 版本低
semver.lt('1.2.3', '9.8.7') // true
// 判断符合某个版本范围的最低版本
semver.minVersion('>=1.0.0') // '1.0.0'
CLI 相关
见之前的文章:实现 CLI 常用工具包 - 终端交互相关(问卷、彩色文字、loading、进度条)
总结
这篇文章到这里就结束了,本文整理了一些在 Node 开发时常用的 NPM
包,希望能够帮到你。但是社区之大,功能强大的 NPM
包远不止这些,可以自行探索。
需要使用某个功能的 NPM
包时,可以在 NPM
官网或者 GitHub
上搜索:
NPM 官网:https://www./[15]
参考资料
[1]https://github.com/isaacs/node-glob: https://github.com/isaacs/node-glob
[2]文档: https://github.com/isaacs/node-glob#options
[3]https://github.com/sindresorhus/globby: https://github.com/sindresorhus/globby
[4]https://github.com/jprichardson/node-fs-extra: https://github.com/jprichardson/node-fs-extra
[5]https://github.com/shelljs/shelljs: https://github.com/shelljs/shelljs
[6]https://github.com/moxystudio/node-cross-spawn: https://github.com/moxystudio/node-cross-spawn
[7]hhttps://github.com/isaacs/rimraf: https://github.com/isaacs/rimraf
[8]https://github.com/node-fetch/node-fetch: https://github.com/node-fetch/node-fetch
[9]https://github.com/axios/axios: https://github.com/axios/axios
[10]https://github.com/sindresorhus/open: https://github.com/sindresorhus/open
[11]https://github.com/http-party/http-server: https://github.com/http-party/http-server
[12]https://github.com/pillarjs/path-to-regexp: https://github.com/pillarjs/path-to-regexp
[13]https://github.com/jfromaniello/url-join: https://github.com/jfromaniello/url-join
[14]https://github.com/npm/node-semver: https://github.com/npm/node-semver
[15]https://www./: https://www./