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

相關文章
相關標籤/搜索