共计 9882 个字符,预计需要花费 25 分钟才能阅读完成。
nodejs 交互工具库系列
库 | 作用 |
---|---|
chalk-pipe | 应用更简略的款式字符串创立粉笔款式计划 |
chalk | 正确处理终端字符串款式 |
Commander.js | 残缺的 node.js 命令行解决方案 |
Inquirer.js | 一组通用的交互式命令行用户界面。 |
slash | 零碎门路符解决 |
minimist | 解析参数选项 |
dotenv | 将环境变量从 .env 文件加载到 process.env 中 |
hash-sum | 十分快的惟一哈希生成器 |
deepmerge | 深度合并两个或多个对象的可枚举属性。 |
yaml-front-matter | 解析 yaml 或 json |
resolve | 实现 node 的 require.resolve() 算法,这样就能够异步和同步地应用 require.resolve()代表文件 |
semver | npm 的语义版本器 |
leven | 测量两字符串之间的差别 <br/> 最快的 JS 实现之一 |
lru cache | 删除最近起码应用的项的缓存对象 |
portfinder | 主动寻找 8000 至 65535 内可用端口号 |
ora | 优雅的终端转轮 |
envinfo | 生成故障排除软件问题 (如操作系统、二进制版本、浏览器、已装置语言等) 时所需的通用详细信息的报告 |
memfs | 内存文件系统与 Node’s fs API 雷同实现 |
execa | 针对人类的流程执行 |
nodejs 交互工具库 — chalk-pipe 和 chalk
nodejs 交互工具库 — commander 和 Inquirer
nodejs 交互工具库 — slash, minimist 和 dotenv
nodejs 交互工具库 — hash-sum, deepmerge 和 yaml-front-matter
nodejs 交互工具库 — resolve 和 semver
nodejs 交互工具库 — leven, lru cache 和 portfinder
nodejs 交互工具库 — ora 和 envinfo
nodejs 交互工具库 — memfs 和 execa
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
- Reference
- Relative paths
- API status
- Dependencies
参考
根本罕用的办法场景就这些了, 更残缺的用法能够间接查阅文档
memfs
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
字段设置正确。
参考
根本罕用的办法场景就这些了, 更残缺的用法能够间接查阅文档
execa