Skip to content

Execa

Execa 是对 node:child_process 的 Promise 化封装,用于从 Node.js 运行外部命令。它提供结构化结果、详细错误、可靠的本地二进制解析和跨平台处理。

适合构建脚本、开发工具和 CLI;只需基础子进程控制或需要精确理解进程模型时,直接使用原生 child_process

安装与执行

bash
pnpm add execa
ts
import { execa } from 'execa'

const { stdout } = await execa`git status --short`
console.log(stdout)

模板标签会将插值作为独立参数传递,不需要自行拼接或转义:

ts
import { execa } from 'execa'

const outputDir = 'dist preview'
await execa`mkdir -p ${outputDir}`

不要把不可信输入拼进 shell: true 的命令字符串。默认使用模板标签或命令与参数分离的形式。

常用选项

ts
import { execa } from 'execa'

const result = await execa('pnpm', ['build'], {
  cwd: process.cwd(),
  preferLocal: true,
  reject: false,
  all: true,
})

if (result.exitCode !== 0) {
  console.error(result.all)
}
  • cwd:指定命令工作目录。
  • preferLocal:优先执行项目 node_modules/.bin 中的命令。
  • reject: false:非零退出码时返回结果而非抛出异常。
  • all: true:合并保留 stdoutstderr 的输出顺序。
  • stdio: 'inherit':将子进程输出直接交给当前终端,适合交互式命令。

默认情况下,非零退出码会抛出 ExecaError。异常中包含命令、工作目录、退出码、stdoutstderr,应记录这些字段而不是只输出错误消息。

结束子进程

长时间运行的命令应显式支持取消:

ts
import { execa } from 'execa'

const controller = new AbortController()
const task = execa({ cancelSignal: controller.signal })`pnpm dev`

setTimeout(() => controller.abort(), 5_000)
await task

取消后仍需处理 Promise 拒绝;不要只终止父进程而遗留子进程。

基于 MIT 许可发布