nodejs交互工具库系列
库 | 作用 |
---|---|
chalk-pipe | 使用更简单的样式字符串创建粉笔样式方案 |
chalk | 正确处理终端字符串样式 |
Commander.js | 完整的 node.js 命令行解决方案 |
Inquirer.js | 一组通用的交互式命令行用户界面。 |
slash | 系统路径符处理 |
minimist | 解析参数选项 |
dotenv | 将环境变量从 .env文件加载到process.env中 |
dotenv-expand | 扩展计算机上已经存在的环境变量 |
hash-sum | 非常快的唯一哈希生成器 |
deepmerge | 深度合并两个或多个对象的可枚举属性。 |
yaml-front-matter | 解析yaml或json |
resolve | 实现node的 require.resolve() 算法,这样就可以异步和同步地使用require.resolve()代表文件 |
semver | npm的语义版本器 |
leven | 测量两字符串之间的差异 最快的JS实现之一 |
lru cache | 删除最近最少使用的项的缓存对象 |
portfinder | 自动寻找 8000 至65535 内可用端口号 |
ora | 优雅的终端转轮 |
envinfo | 生成故障排除软件问题(如操作系统、二进制版本、浏览器、已安装语言等)时所需的通用详细信息的报告 |
memfs | 内存文件系统与Node's fs API相同实现 |
execa | 针对人类的流程执行 |
webpack-merge | 用于连接数组和合并对象,从而创建一个新对象 |
webpack-chain | 使用链式API去生成简化webpack版本配置的修改 |
strip-ansi | 从字符串中去掉ANSI转义码 |
address | 获取当前机器的IP, MAC和DNS服务器。 |
default-gateway | 通过对OS路由接口的exec调用获得机器的默认网关 |
joi | JavaScript最强大的模式描述语言和数据验证器。 |
fs-extra | 添加了未包含在原生fs 模块中的文件系统方法,并向fs 方法添加了promise支持 |
Acorn | 一个小而快速的JavaScript解析器,完全用JavaScript编写。 |
zlib.js | ZLIB.js是ZLIB(RFC1950), DEFLATE(RFC1951), GZIP(RFC1952)和PKZIP在JavaScript实现。 |
nodejs交互工具库 -- chalk-pipe和chalk
nodejs交互工具库 -- commander和Inquirer
nodejs交互工具库 -- slash, minimist和dotenv, dotenv-expand
nodejs交互工具库 -- hash-sum, deepmerge和yaml-front-matter
nodejs交互工具库 -- leven, lru cache和portfinder
nodejs交互工具库 -- webpack-merge和webpack-chain
nodejs交互工具库 -- strip-ansi, address, default-gateway和joi
nodejs交互工具库 -- fs-extra, Acorn和zlib
memfs
内存文件系统与Node's fs
API相同实现
- Node's
fs
API 实现, 查阅API Status - 在内存中存储文件
Buffer
- 像Node.js一样抛出sameish*错误
- 有i-nodes的概念
- 实现硬链接
- 实现软链接(又名符号链接、符号链接)
- 权限可能在未来被实现
- 可以在浏览器中使用, 查阅
memfs-webpack
Install
npm install --save memfs
Usage
import { fs } from 'memfs';
fs.writeFileSync('/hello.txt', 'World!');
fs.readFileSync('/hello.txt', 'utf8'); // World!
从一个普通JSON创建一个文件系统
import { fs, vol } from 'memfs';
const json = {
'./README.md': '1',
'./src/index.js': '2',
'./node_modules/debug/index.js': '3',
};
vol.fromJSON(json, '/app');
fs.readFileSync('/app/README.md', 'utf8'); // 1
vol.readFileSync('/app/src/index.js', 'utf8'); // 2
导出 JSON:
vol.writeFileSync('/script.sh', 'sudo rm -rf *');
vol.toJSON(); // {"/script.sh": "sudo rm -rf *"}
用来测试
vol.writeFileSync('/foo', 'bar');
expect(vol.toJSON()).toEqual({ '/foo': 'bar' });
创建您需要的文件系统卷:
import { Volume } from 'memfs';
const vol = Volume.fromJSON({ '/foo': 'bar' });
vol.readFileSync('/foo'); // bar
const vol2 = Volume.fromJSON({ '/foo': 'bar 2' });
vol2.readFileSync('/foo'); // bar 2
使用 memfs
和unionfs
从内存卷和实际磁盘文件系统创建一个文件系统:
import * as fs from 'fs';
import { ufs } from 'unionfs';
ufs.use(fs).use(vol);
ufs.readFileSync('/foo'); // bar
使用fs-monkey
对monkey-patch Node's require
函数:
import { patchRequire } from 'fs-monkey';
vol.writeFileSync('/index.js', 'console.log("hi world")');
patchRequire(vol);
require('/index'); // hi world
Docs
参考
基本常用的方法场景就这些了,更完整的用法可以直接查阅文档
execa
针对人类的流程执行
Why
这个包改进了child_process
方法:
- Promise接口
- 从输出中删除最后的换行符,这样您就不必执行
stdout.trim()
- 支持跨平台的shebang二进制文件
- 改进Windows支持。
- 更高的最大缓冲区。100mb而不是200kb。
- 按名称执行本地安装的二进制文件。
- 在父进程终止时清除派生的进程。
- 从
stdout
和stderr
获得交错输出,类似于在终端上打印的输出。(异步) - 可以指定文件和参数作为一个单一的字符串没有外壳
- 更具描述性的错误。
Install
$ npm install execa
Usage
const execa = require('execa');
(async () => {
const {stdout} = await execa('echo', ['unicorns']);
console.log(stdout);
//=> 'unicorns'
})();
通过管道将子进程stdout传输到父进程
const execa = require('execa');
execa('echo', ['unicorns']).stdout.pipe(process.stdout);
错误处理
const execa = require('execa');
(async () => {
// Catching an error
try {
await execa('unknown', ['command']);
} catch (error) {
console.log(error);
/*
{
message: 'Command failed with ENOENT: unknown command spawn unknown ENOENT',
errno: -2,
code: 'ENOENT',
syscall: 'spawn unknown',
path: 'unknown',
spawnargs: ['command'],
originalMessage: 'spawn unknown ENOENT',
shortMessage: 'Command failed with ENOENT: unknown command spawn unknown ENOENT',
command: 'unknown command',
stdout: '',
stderr: '',
all: '',
failed: true,
timedOut: false,
isCanceled: false,
killed: false
}
*/
}
})();
取消派生的进程
const execa = require('execa');
(async () => {
const subprocess = execa('node');
setTimeout(() => {
subprocess.cancel();
}, 1000);
try {
await subprocess;
} catch (error) {
console.log(subprocess.killed); // true
console.log(error.isCanceled); // true
}
})()
用同步方法捕获错误
try {
execa.sync('unknown', ['command']);
} catch (error) {
console.log(error);
/*
{
message: 'Command failed with ENOENT: unknown command spawnSync unknown ENOENT',
errno: -2,
code: 'ENOENT',
syscall: 'spawnSync unknown',
path: 'unknown',
spawnargs: ['command'],
originalMessage: 'spawnSync unknown ENOENT',
shortMessage: 'Command failed with ENOENT: unknown command spawnSync unknown ENOENT',
command: 'unknown command',
stdout: '',
stderr: '',
all: '',
failed: true,
timedOut: false,
isCanceled: false,
killed: false
}
*/
}
杀死一个过程
使用SIGTERM, 2秒后,用SIGKILL杀死它。
const subprocess = execa('node');
setTimeout(() => {
subprocess.kill('SIGTERM', {
forceKillAfterTimeout: 2000
});
}, 1000);
API
execa(file, arguments, options?)
执行一个文件。可以把它看作是 child_process.execFile()
和child_process.spawn()
的混合.
不需要转义/引用。
除非使用shell
选项,否则没有shell解释器(Bash, cmd.exe
, 等),因此不允许使用shell特性,如变量替换(echo $PATH)。
返回其中一个child_process实例:
- 总是一个带有
childProcessResult
的成功或者失败态的Promise
. - 公开下列附加方法和属性。
kill(signal?, options?)
与原来的 child_process#kill()
相同,除了:如果signal
是SIGTERM
(默认值),并且子进程在5秒后没有终止,通过发送SIGKILL
强制执行。
options.forceKillAfterTimeout
Type: number | false
Default: 5000
在发送前等待子进程终止的毫秒 SIGKILL
.
可以设置false
禁用.
cancel()
类似于childProcess.kill()
。当取消子进程执行时,这是首选的,因为错误更具有描述性和 childProcessResult.scancelled
被设置为true
。
all
Type: ReadableStream | undefined
流合并/交错stdout
和stderr
.
这是 undefined
如果满足其中:
- all选项为false(默认值)
stdout
和stderr
选项都被设置为'inherit'
,'ipc'
,Stream
或者integer`
execa.sync(file, arguments?, options?)
同步执行文件。
返回或抛出childProcessResult
.
execa.command(command, options?)
与execa()
相同,只是文件和参数都在单个命令字符串中指定。例如,execa('echo', ['unicorns'])
与execa.command('echo unicorns')
相同。
如果文件或参数包含空格,则必须使用反斜杠对它们进行转义。如果command
不是常量而是变量,例如__dirname
或 process.cwd()
是剩余的,那么这一点尤其重要。除空格外,不需要转义/引号。
如果命令使用特定于shell的特性,则必须使用shell选项,而不是一个后面跟着参数的简单文件。
execa.commandSync(command, options?)
与 execa.command()
相同,但是是同步的。
返回或抛出一个 childProcessResult
。
execa.node(scriptPath, arguments?, options?)
将Node.js脚本作为子进程执行。
等同于 execa('node', [scriptPath, ...arguments], options)
除了(如child_process#fork()
)
- 使用当前Node版本和选项。这可以使用
nodePath
和nodeOptions
选项覆盖。 - 不能使用
shell
选项 - 一个额外的通道ipc被传递给
stdio
childProcessResult
Type: object
子进程执行的结果。关于成功,这是一个简单的目标。对于失败,这也是一个错误实例。
子进程在:
- 它的退出代码不是0
- 它被一个信号杀死了
- 定时失效
- 被取消了
- 没有足够的内存或者子进程已经太多了
command
Type: string
运行的文件和参数。
exitCode
Type: number
已运行进程的数字退出代码。
stdout
Type: string | Buffer
进程在stdout上的输出。
stderr
Type: string | Buffer
进程在stderr上的输出。
all
Type: string | Buffer | undefined
使用 stdout
和stderr
的进程的输出是交错的。
这是 undefined
如果满足其中:
all
项是false
(默认值)execa.sync()
使用
failed
Type: boolean
进程是否运行失败。
timedOut
Type: boolean
进程是否超时。
isCanceled
Type: boolean
进程是否已取消。
killed
Type: boolean
进程是否被终止。
signal
Type: string | undefined
用于终止进程的信号的名称。例如, SIGFPE
.
如果一个信号终止了进程,则定义此属性并将其包含在错误消息中。否则它是 undefined
.
signalDescription
Type: string | undefined
对用于终止过程的信号的人性化描述。例如 Floating point arithmetic error
.
如果一个信号终止了进程,则定义此属性并将其包含在错误消息中。否则它是 undefined
.当信号非常不常见,而这种情况很少发生时,它也是undefined
。
message
Type: string
子进程运行失败时的错误消息。除了底层错误消息外,它还包含一些与子进程出错原因相关的信息。
子进程 stderr
然后stdout
被追加到末尾,用新行分隔,不交叉。
shortMessage
Type: string
这与 message
属性相同,只是它不包含子进程stdout/stderr
。
originalMessage
Type: string | undefined
原始错误消息。这与 message
属性相同,只是它既不包含子进程stdout/stderr
,也不包含Execa添加的一些附加信息。
这是undefined
,除非子进程由于错误事件或超时而退出。
options
Type: object
cleanup
Type: boolean
Default: true
当父进程退出时终止派生进程,除非:-派生进程分离-父进程突然终止,例如,使用 SIGKILL
而不是SIGTERM
或正常退出
preferLocal
Type: boolean
Default: false
在寻找要执行的二进制文件时,首选本地安装的二进制文件。
如果你 $ npm install foo
, 你可以 execa('foo')
.
localDir
Type: string
Default: process.cwd()
查找本地安装的二进制文件的首选路径 (使用 preferLocal
).
execPath
Type: string
Default: process.execPath
(当前的node . js可执行)
要在子进程中使用的Node.js可执行文件的路径。
这可以是绝对路径,也可以是相对于 cwd
选项的路径。
要求 preferLocal
为true
.
例如,它可以与 get-node
一起使用,在子进程中运行特定的Node.js版本。
buffer
Type: boolean
Default: true
缓冲生成的进程的输出。当设置为 false
, 必须读取 stdout
和stderr
的输出(如果 all
选项为真,则读取all
)。否则,返回的promise将不会被resolved/rejected。
如果衍生的进程失败, error.stdout
, error.stderr
, 和error.all
将包含缓冲数据。
input
Type: string | Buffer | stream.Readable
向二进制文件的 stdin
中写入一些输入。
在使用同步方法时不允许使用流。
stdin
Type: string | number | Stream | undefined
Default: pipe
stdio
相同的选项.
stdout
Type: string | number | Stream | undefined
Default: pipe
stdio
相同的选项.
stderr
Type: string | number | Stream | undefined
Default: pipe
stdio
相同的选项.
all
Type: boolean
Default: false
在承诺和解析值上添加.all属性。该属性包含交错使用stdout和stderr的进程的输出。
reject
Type: boolean
Default: true
将此设置为 false
将解决带有错误的承诺,而不是拒绝它。
stripFinalNewline
Type: boolean
Default: true
从输出中去掉最后的换行符。
extendEnv
Type: boolean
Default: true
如果在提供 env
属性时不希望扩展环境变量,则设置为false
。
Execa还接受以下选项,这些选项与的选项相同child_process#spawn()
/child_process#exec()
cwd
Type: string
Default: process.cwd()
子进程的当前工作目录。
env
Type: object
Default: process.env
环境key-value对。自动从 process.env
扩展。如果你不想这样做,请将extendEnv
设置为false
。
argv0
Type: string
显式设置发送给子进程的 argv[0]
的值。如果未指定,将设置为 file
。
stdio
Type: string | string[]
Default: pipe
子stdio 配置.
serialization
Type: string
Default: 'json'
当使用 stdio: 'ipc'
选项或exec. node()
时,指定用于在进程之间发送消息的序列化类型:- json
:使用json .stringify()
和json .parse()
。- advanced
:使用v8.serialize()
需要Node.js13.2.0
或更高版本。
detached
Type: boolean
让子进程独立于父进程运行。具体的行为取决于平台。
uid
Type: number
设置进程的用户标识。
gid
Type: number
设置流程的组标识。
shell
Type: boolean | string
Default: false
如果为真,则在shell中运行文件。在UNIX上使用 /bin/sh
,在Windows上使用cmd.exe
。可以将不同的shell指定为字符串。shell应该理解UNIX上的-c
开关或Windows上的/d /s /c
开关。
我们建议不要使用此选项,因为它是:
- 不是跨平台的,鼓励shell特定的语法。
- 较慢,因为附加了shell解释。
- 不安全,可能允许命令注入
encoding
Type: string | null
Default: utf8
指定用于解码 stdout
和stderr
输出的字符编码。如果设置为null
,那么stdout
和stderr
将是缓冲区而不是字符串。
timeout
Type: number
Default: 0
如果超时时间大于 0
,如果子线程运行的时间超过超时毫秒,父线程将发送killSignal
属性标识的信号(默认为SIGTERM
)。
maxBuffer
Type: number
Default: 100_000_000
(100 MB)
允许的最大字节数据量的 stdout
或者stderr
.
killSignal
Type: string | number
Default: SIGTERM
当派生的进程将被终止时使用的信号值。
windowsVerbatimArguments
Type: boolean
Default: false
如果为真,则不会在Windows上引用或转义参数。在其他平台上被忽略。当shell选项为真时,这将自动设置为真。
windowsHide
Type: boolean
Default: true
在Windows上,不要创建新的控制台窗口。请注意,这也会阻止 CTRL-C
在Windows
上工作。
nodePath (For .node()
only)
Type: string
Default: process.execPath
用于创建子进程的可执行文件。
nodeOptions (For .node()
only)
Type: string[]
Default: process.execArgv
传递给Node.js可执行文件的CLI选项列表。
Tips
Retry on error
通过使用自动重试和p-retry
包指数返回(exponential backoff)来优雅地处理失败:
const pRetry = require('p-retry');
const run = async () => {
const results = await execa('curl', ['-sSL', 'https://sindresorhus.com/unicorn']);
return results;
};
(async () => {
console.log(await pRetry(run, {retries: 5}));
})();
Save and pipe output from a child process
假设您希望实时显示子进程的输出,同时将其保存到一个变量中。
const execa = require('execa');
const subprocess = execa('echo', ['foo']);
subprocess.stdout.pipe(process.stdout);
(async () => {
const {stdout} = await subprocess;
console.log('child output:', stdout);
})();
Redirect output to a file
const execa = require('execa');
const subprocess = execa('echo', ['foo'])
subprocess.stdout.pipe(fs.createWriteStream('stdout.txt'))
Redirect input from a file
const execa = require('execa');
const subprocess = execa('cat')
fs.createReadStream('stdin.txt').pipe(subprocess.stdin)
Execute the current package's binary
const {getBinPathSync} = require('get-bin-path');
const binPath = getBinPathSync();
const subprocess = execa(binPath);
可以将execa
与get-bin-path
结合使用,以测试当前包的二进制代码。与硬编码到二进制文件的路径相反,这验证了 package.json
bin
字段设置正确。
参考
基本常用的方法场景就这些了,更完整的用法可以直接查阅文档