Gulp.js command execution for humans.
As opposed to similar plugins or to
child_process.exec()
,
this uses Execa which provides:
- Better Windows support, including shebangs
- Faster and more secure commands, since no shell is used by default
- Execution of locally installed binaries
- Interleaved
stdout
/stderr
gulp-execa
adds Gulp-specific features to
Execa including:
- a task shortcut syntax
- configurable verbosity
- better errors
Commands can be executed either directly or inside a files stream. In streaming mode, unlike other libraries:
- commands are run in parallel, not serially
- output can be saved either in files or in variables
Please reach out if you're looking for a Node.js API or CLI engineer (11 years of experience). Most recently I have been Netlify Build's and Netlify Plugins' technical lead for 2.5 years. I am available for full-time remote positions.
gulpfile.js
:
import { pipeline } from 'node:stream/promises'
import gulp from 'gulp'
import { exec, stream, task } from 'gulp-execa'
export const audit = task('npm audit')
export const outdated = async () => {
await exec('npm outdated')
}
export const sort = () =>
pipeline(
gulp.src('*.txt'),
stream(({ path }) => `sort ${path}`),
gulp.dest('sorted'),
)
npm install -D gulp-execa
This plugin requires Gulp 5 and Node.js >=18.18.0. It is an ES module and must
be loaded using
an import
or import()
statement,
not require()
. If TypeScript is used, it must be configured to
output ES modules,
not CommonJS.
Returns a Gulp task that executes command
.
import { task } from 'gulp-execa'
export const audit = task('npm audit')
Executes command
. The return value is both a promise and a
child_process
instance.
The promise will be resolved with the
command result. If
the command failed, the promise will be rejected with a nice
error. If the
reject: false
option was used,
the promise will be resolved with that error instead.
import { exec } from 'gulp-execa'
export const outdated = async () => {
await exec('npm outdated')
}
Returns a stream that executes a command
on each input file.
function
must:
- take a Vinyl file
as argument. The most useful property is
file.path
but other properties are available as well. - return either:
- a
command
string - an
options
object with acommand
property undefined
- a
import { pipeline } from 'node:stream/promises'
import gulp from 'gulp'
import { stream } from 'gulp-execa'
export const sort = () =>
pipeline(
gulp.src('*.txt'),
stream(({ path }) => `sort ${path}`),
gulp.dest('sorted'),
)
Each file in the stream will spawn a separate process. This can consume lots of resources so you should only use this method when there are no alternatives such as:
- firing a command programmatically instead of spawning a child process
- passing several files, a directory or a globbing pattern as arguments to the command
The debug
,
stdout
,
stderr
,
all
and
stdio
options cannot be used
with this method.
By default no shell interpreter (like Bash or cmd.exe
) is used. This means
command
must be just the program and its arguments. No escaping/quoting is
needed, except for significant spaces (with a backslash).
Shell features such as globbing, variables and operators (like &&
>
;
)
should not be used. All of this can be done directly in Node.js instead.
Shell interpreters are slower, less secure and less cross-platform. However, you
can still opt-in to using them with the
shell
option.
import { writeFileStream } from 'node:fs'
import gulp from 'gulp'
import { task } from 'gulp-execa'
// Wrong
// export const check = task('npm audit && npm outdated')
// Correct
export const check = gulp.series(task('npm audit'), task('npm outdated'))
// Wrong
// export const install = task('npm install > log.txt')
// Correct
export const install = task('npm install', {
stdout: writeFileStream('log.txt'),
})
options
is an optional object.
All Execa options can be used. Please refer to its documentation for a list of possible options.
The following options are available as well.
Type: boolean
Default: debug
option's value
Whether the command
should be printed on the console.
$ gulp audit
[13:09:39] Using gulpfile ~/code/gulpfile.js
[13:09:39] Starting 'audit'...
[13:09:39] [gulp-execa] npm audit
[13:09:44] Finished 'audit' after 4.96 s
Type: boolean
Default: true
for task()
and
exec()
, false
for
stream()
.
Whether both the command
and its output (stdout
/stderr
) should be printed
on the console instead of being returned in JavaScript.
$ gulp audit
[13:09:39] Using gulpfile ~/code/gulpfile.js
[13:09:39] Starting 'audit'...
[13:09:39] [gulp-execa] npm audit
== npm audit security report ===
found 0 vulnerabilities
in 27282 scanned packages
[13:09:44] Finished 'audit' after 4.96 s
Type: string
Value: 'replace'
or 'save'
Default: 'replace'
With stream()
, whether the command result should:
replace
the file's contentssave
: be pushed to thefile.execa
array property
import { pipeline } from 'node:stream/promises'
import gulp from 'gulp'
import { stream } from 'gulp-execa'
import through from 'through2'
export const task = () =>
pipeline(
gulp.src('*.js'),
// Prints the number of lines of each file
stream(({ path }) => `wc -l ${path}`, { result: 'save' }),
through.obj((file, encoding, func) => {
console.log(file.execa[0].stdout)
func(null, file)
}),
)
Type: string
Value: 'stdout'
, 'stderr'
or 'all'
Default: 'stdout'
Which output stream to use with result: 'replace'
.
import { pipeline } from 'node:stream/promises'
import gulp from 'gulp'
import { stream } from 'gulp-execa'
import through from 'through2'
export const task = () =>
pipeline(
gulp.src('*.js'),
// Prints the number of lines of each file, including `stderr`
stream(({ path }) => `wc -l ${path}`, { result: 'replace', from: 'all' }),
through.obj((file, encoding, func) => {
console.log(file.contents.toString())
func(null, file)
}),
)
Type: integer
Default: 100
With stream()
, how many commands to run in parallel
at once.
For any question, don't hesitate to submit an issue on GitHub.
Everyone is welcome regardless of personal background. We enforce a Code of conduct in order to promote a positive and inclusive environment.
This project was made with ❤️. The simplest way to give back is by starring and sharing it online.
If the documentation is unclear or has a typo, please click on the page's Edit
button (pencil icon) and suggest a correction.
If you would like to help us fix a bug or add a new feature, please check our guidelines. Pull requests are welcome!
Thanks go to our wonderful contributors:
ehmicky 💻 🎨 🤔 📖 | Jonathan Haines 🐛 |