nodejs交互工具库 -- memfs和execa

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 测量两字符串之间的差别<br/>最快的JS实现之一
lru cache 删除最近最少使用的项的缓存对象
portfinder 自动寻找 800065535内可用端口号
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和chalkhtml

nodejs交互工具库 -- commander和Inquirernode

nodejs交互工具库 -- slash, minimist和dotenv, dotenv-expandwebpack

nodejs交互工具库 -- hash-sum, deepmerge和yaml-front-mattergit

nodejs交互工具库 -- resolve和semvergithub

nodejs交互工具库 -- leven, lru cache和portfinderweb

nodejs交互工具库 -- ora和envinfo算法

nodejs交互工具库 -- memfs和execashell

nodejs交互工具库 -- webpack-merge和webpack-chainnpm

nodejs交互工具库 -- strip-ansi, address, default-gateway和joijson

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

使用 memfsunionfs从内存卷和实际磁盘文件系统建立一个文件系统:

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

参考

基本经常使用的方法场景就这些了,更完整的用法能够直接查阅文档

memfs

execa

针对人类的流程执行

Why

这个包改进了child_process方法:

  • Promise接口
  • 从输出中删除最后的换行符,这样您就没必要执行stdout.trim()
  • 支持跨平台的shebang二进制文件
  • 改进Windows支持。
  • 更高的最大缓冲区。100mb而不是200kb。
  • 按名称执行本地安装的二进制文件。
  • 在父进程终止时清除派生的进程。
  • stdoutstderr得到交错输出,相似于在终端上打印的输出。(异步)
  • 能够指定文件和参数做为一个单一的字符串没有外壳
  • 更具描述性的错误。

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()相同,除了:若是signalSIGTERM(默认值),而且子进程在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不是常量而是变量,例如__dirnameprocess.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版本和选项。这可使用 nodePathnodeOptions选项覆盖。
  • 不能使用 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

使用 stdoutstderr的进程的输出是交错的。

这是 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选项的路径。

要求 preferLocaltrue.

例如,它能够与 get-node一块儿使用,在子进程中运行特定的Node.js版本。

buffer

Type: boolean
Default: true

缓冲生成的进程的输出。当设置为 false, 必须读取 stdoutstderr的输出(若是 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

指定用于解码 stdoutstderr输出的字符编码。若是设置为null,那么stdoutstderr将是缓冲区而不是字符串。

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-CWindows上工做。

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);

能够将execaget-bin-path结合使用,以测试当前包的二进制代码。与硬编码到二进制文件的路径相反,这验证了 package.json bin字段设置正确。

参考

基本经常使用的方法场景就这些了,更完整的用法能够直接查阅文档

execa

相关文章
相关标签/搜索