开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 12 天,点击查看活动详情
近期,Vue 3.2发布,出于好奇,去瞄了一眼Vue 3.2的源码,发现其中有一个execa库很有意思,于是去学习了一番。在学习的基础上,写了这篇总结。本文主要介绍execa的概念、常用API以及execa在Vue3.x中的使用。
1、execa简介
execa的文档中对其的介绍如下:
Process execution for humans
人类的流程执行
换成人话,execa是一个子进程(child_process)管理库。
Node官网上对 child_process的介绍如下:
child_process模块提供了以与 popen(3)类似但不完全相同的方式衍生子进程的能力
Node的child_process提供了exec、expecFile、spawn和fork。
execa是对child_process的改进:
-
提供Promise接口
-
输出会删除最后的换行符,不必执行stdout.trim()
-
支持跨平台的shebang(#!)二进制文件
-
Windows支持友好
-
最大缓冲区为100MB而不是200kb。
-
可以按名称执行本地安装的二进制文件
-
在父进程终止时清除派生的进程
-
从
stdout
和stderr
获得交错输出,类似于在终端上打印的输出。(异步) -
可以指定文件和参数作为一个单一的字符串
-
报错更具描述性
由此可知,execa是一个加强版的子进程管理库。如果想要运行一个 shell 命令或者生成一个子进程,execa 是一个较好的选择。
2、execa使用
这里主要是execa的安装、基本API以及错误捕获使用。
- 安装
yarn add execa --dev
OR
npm instal execa --save-dev
……
"scripts": {
"echo": "node scripts/echo.js",
"err": "node scripts/err.js"
},
"devDependencies": {
"execa": "^5.1.1",
}
……
- 使用
const execa = require('execa');
(async () => {
const {stdout} = await execa('echo', ['unicorns']);
console.log(stdout);
//=> 'unicorns'
})();
- 错误处理
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
}
*/
}
})();
3、API介绍
execa()、execa.sync()、execa.command、execa.commandSync、execa.node是execa的几个比较常用的API。这几个API的介绍如下:
API | 解释 |
---|---|
execa(file, arguments, options?) | 相当于child_process.execFile() 和child_process.spawn() |
execa.sync(file, arguments?, options?) | 同步执行文件 |
execa.command(command, options?) | 与execa()相同,上文中execa('echo', ['unicorns'])与execa.command('echo unicorns')相同 |
execa.commandSync(command, options?) | 与execa.sync()相同 |
execa.node(scriptPath, arguments?, options?) | 执行Node脚本 |
参数说明如下:
- file:将要运行的命令;
- arguments:参数数组;
- options:选项对象,如用shell,可以设置为{shell:true}。
- command:命令+参数的集合;
- scriptPath: 运行模块路径;
其中,?修饰的参数是可以省参数。
execa()的源码如下:
const execa = (file, args, options) => {
...
return mergePromise(spawned, handlePromiseOnce);
}
...
// The return value is a mixin of `childProcess` and `Promise`
const mergePromise = (spawned, promise) => {
for (const [property, descriptor] of descriptors) {
// Starting the main `promise` is deferred to avoid consuming streams
const value = typeof promise === 'function' ?
(...args) => Reflect.apply(descriptor.value, promise(), args) :
descriptor.value.bind(promise);
Reflect.defineProperty(spawned, property, {...descriptor, value});
}
return spawned;
};
...
module.exports = execa;
execa()的源码如下:
module.exports.sync = (file, args, options) => {
...
result = childProcess.spawnSync(parsed.file, parsed.args, parsed.options);
...
const stdout = handleOutput(parsed.options, result.stdout, result.error);
const stderr = handleOutput(parsed.options, result.stderr, result.error);
return {
command,
escapedCommand,
exitCode: 0,
stdout,
stderr,
failed: false,
timedOut: false,
isCanceled: false,
killed: false
};
}
execa.command()的源码如下:
// https://github.com/sindresorhus/execa/blob/main/index.js
// ...
module.exports.command = (command, options) => {
const [file, ...args] = parseCommand(command);
return execa(file, args, options);
};
// ...
execa.node() 的源码如下:
module.exports.node = (scriptPath, args, options = {}) => {
if (args && !Array.isArray(args) && typeof args === 'object') {
options = args;
args = [];
}
const stdio = normalizeStdio.node(options);
const defaultExecArgv = process.execArgv.filter(arg => !arg.startsWith('--inspect'));
const {
nodePath = process.execPath,
nodeOptions = defaultExecArgv
} = options;
return execa(
nodePath,
[
...nodeOptions,
scriptPath,
...(Array.isArray(args) ? args : [])
],
{
...options,
stdin: undefined,
stdout: undefined,
stderr: undefined,
stdio,
shell: false
}
);
};
4、 Vue 3.x中execa的应用
Vue 3.x中execa的应用如下图1所示。Vue2.x中类似功能如图2所示。通过Vue 3.x与Vue 2.x的scripts比较可知,execa在Vue 3.x中不仅可以为scripts提供兼容性,特别是Windows系统、Mac OS系统、Linux系统,同时可以提供扩展性,可以动态添加参数。
图 1
图 2
5、参考资料
有bug?想补充?
感谢大家观看这篇文章,有任何问题或想和我交流,请直接留言,
发现文章有不妥之处,也可指出交流,感谢阅读~