From eff6b24c62caecd4feea7d90af5ca7d81b129096 Mon Sep 17 00:00:00 2001
From: Yoshiya Hinosawa
Date: Sat, 7 Nov 2015 17:39:17 +0900
Subject: [PATCH 001/216] Add browserify (multiple destination) example
---
docs/recipes/README.md | 1 +
.../browserify-multiple-destination.md | 43 +++++++++++++++++++
2 files changed, 44 insertions(+)
create mode 100644 docs/recipes/browserify-multiple-destination.md
diff --git a/docs/recipes/README.md b/docs/recipes/README.md
index 37096cf83..235fd734d 100644
--- a/docs/recipes/README.md
+++ b/docs/recipes/README.md
@@ -20,5 +20,6 @@
* [Using multiple sources in one task](using-multiple-sources-in-one-task.md)
* [Browserify + Uglify with sourcemaps](browserify-uglify-sourcemap.md)
* [Browserify + Globs](browserify-with-globs.md)
+* [Browserify + Globs (multiple destination)](browserify-multiple-destination.md)
* [Output both a minified and non-minified version](minified-and-non-minified.md)
* [Templating with Swig and YAML front-matter](templating-with-swig-and-yaml-front-matter.md)
diff --git a/docs/recipes/browserify-multiple-destination.md b/docs/recipes/browserify-multiple-destination.md
new file mode 100644
index 000000000..3df6cc79c
--- /dev/null
+++ b/docs/recipes/browserify-multiple-destination.md
@@ -0,0 +1,43 @@
+# Browserify + Globs (multiple destination)
+
+This example shows how to set up a task of bundling multiple entry points into multiple destinations using browserify.
+
+The below `js` task bundles all the `.js` files under `src/` as entry points and writes the results under `dest/`.
+
+
+```js
+var gulp = require('gulp');
+var plugins = require('gulp-load-plugins')();
+var browserify = require('browserify');
+var gutil = require('gulp-util');
+
+gulp.task('js', function () {
+
+ return gulp.src('src/**/*.js', {base: 'src'})
+
+ // transform file objects using gulp-map plugin
+ .pipe(plugins.tap(function (file) {
+
+ gutil.log('bundling ' + file.path);
+
+ // replace file contents with browserify's bundle stream
+ file.contents = browserify(file.path, {debug: true}).bundle();
+
+ }))
+
+ // transform streaming contents into buffer contents (because gulp-sourcemaps does not support streaming contents)
+ .pipe(plugins.buffer())
+
+ // load and init sourcemaps
+ .pipe(plugins.sourcemaps.init({loadMaps: true}))
+
+ // uglify
+ .pipe(plugins.uglify())
+
+ // write sourcemaps
+ .pipe(plugins.sourcemaps.write('./'))
+
+ .pipe(gulp.dest('dest'));
+
+});
+```
From 3407b2ad8c46d72e2ab252e75fb4ebb382a4f838 Mon Sep 17 00:00:00 2001
From: Yoshiya Hinosawa
Date: Tue, 10 Nov 2015 13:30:14 +0900
Subject: [PATCH 002/216] Do not use gulp-load-plugins
and fix an error in comment
---
.../recipes/browserify-multiple-destination.md | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/docs/recipes/browserify-multiple-destination.md b/docs/recipes/browserify-multiple-destination.md
index 3df6cc79c..f57584de9 100644
--- a/docs/recipes/browserify-multiple-destination.md
+++ b/docs/recipes/browserify-multiple-destination.md
@@ -7,16 +7,19 @@ The below `js` task bundles all the `.js` files under `src/` as entry points and
```js
var gulp = require('gulp');
-var plugins = require('gulp-load-plugins')();
var browserify = require('browserify');
var gutil = require('gulp-util');
+var tap = require('gulp-tap');
+var buffer = require('gulp-buffer');
+var sourcemaps = require('gulp-sourcemaps');
+var uglify = require('gulp-uglify');
gulp.task('js', function () {
return gulp.src('src/**/*.js', {base: 'src'})
- // transform file objects using gulp-map plugin
- .pipe(plugins.tap(function (file) {
+ // transform file objects using gulp-tap plugin
+ .pipe(tap(function (file) {
gutil.log('bundling ' + file.path);
@@ -26,16 +29,15 @@ gulp.task('js', function () {
}))
// transform streaming contents into buffer contents (because gulp-sourcemaps does not support streaming contents)
- .pipe(plugins.buffer())
+ .pipe(buffer())
// load and init sourcemaps
- .pipe(plugins.sourcemaps.init({loadMaps: true}))
+ .pipe(sourcemaps.init({loadMaps: true}))
- // uglify
- .pipe(plugins.uglify())
+ .pipe(uglify())
// write sourcemaps
- .pipe(plugins.sourcemaps.write('./'))
+ .pipe(sourcemaps.write('./'))
.pipe(gulp.dest('dest'));
From 284b6ab1de502735e2c4986f861f19dc7371f790 Mon Sep 17 00:00:00 2001
From: Yoshiya Hinosawa
Date: Tue, 22 Dec 2015 13:22:17 +0900
Subject: [PATCH 003/216] Add `read: false` option in gulp.src and remove
`base: 'src'` option
---
docs/recipes/browserify-multiple-destination.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/recipes/browserify-multiple-destination.md b/docs/recipes/browserify-multiple-destination.md
index f57584de9..6a9af199a 100644
--- a/docs/recipes/browserify-multiple-destination.md
+++ b/docs/recipes/browserify-multiple-destination.md
@@ -16,7 +16,7 @@ var uglify = require('gulp-uglify');
gulp.task('js', function () {
- return gulp.src('src/**/*.js', {base: 'src'})
+ return gulp.src('src/**/*.js', {read: false}) // no need of reading file because browserify does.
// transform file objects using gulp-tap plugin
.pipe(tap(function (file) {
From 59ddc255496b5b5881c5f471973c1842b5ac7a4c Mon Sep 17 00:00:00 2001
From: Logan Arnett
Date: Wed, 3 Feb 2016 10:14:40 -0500
Subject: [PATCH 004/216] make comments easier to comprehend
---
docs/recipes/running-task-steps-per-folder.md | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/docs/recipes/running-task-steps-per-folder.md b/docs/recipes/running-task-steps-per-folder.md
index b1bf4632c..2a3113eed 100644
--- a/docs/recipes/running-task-steps-per-folder.md
+++ b/docs/recipes/running-task-steps-per-folder.md
@@ -40,17 +40,12 @@ gulp.task('scripts', function() {
var folders = getFolders(scriptsPath);
var tasks = folders.map(function(folder) {
- // concat into foldername.js
- // write to output
- // minify
- // rename to folder.min.js
- // write to output again
return gulp.src(path.join(scriptsPath, folder, '/**/*.js'))
- .pipe(concat(folder + '.js'))
- .pipe(gulp.dest(scriptsPath))
- .pipe(uglify())
- .pipe(rename(folder + '.min.js'))
- .pipe(gulp.dest(scriptsPath));
+ .pipe(concat(folder + '.js')) // concat into foldername.js
+ .pipe(gulp.dest(scriptsPath)) // write to output
+ .pipe(uglify()) // minify
+ .pipe(rename(folder + '.min.js')) // rename to folder.min.js
+ .pipe(gulp.dest(scriptsPath)); // write to output again
});
// process all remaining files in scriptsPath root into main.js and main.min.js files
From 9b697393e34a170fe65335f578b7a7a6d8aa94d8 Mon Sep 17 00:00:00 2001
From: Logan Arnett
Date: Wed, 3 Feb 2016 14:01:35 -0500
Subject: [PATCH 005/216] comments above each pipe
---
docs/recipes/running-task-steps-per-folder.md | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/docs/recipes/running-task-steps-per-folder.md b/docs/recipes/running-task-steps-per-folder.md
index 2a3113eed..905f697b9 100644
--- a/docs/recipes/running-task-steps-per-folder.md
+++ b/docs/recipes/running-task-steps-per-folder.md
@@ -41,11 +41,16 @@ gulp.task('scripts', function() {
var tasks = folders.map(function(folder) {
return gulp.src(path.join(scriptsPath, folder, '/**/*.js'))
- .pipe(concat(folder + '.js')) // concat into foldername.js
- .pipe(gulp.dest(scriptsPath)) // write to output
- .pipe(uglify()) // minify
- .pipe(rename(folder + '.min.js')) // rename to folder.min.js
- .pipe(gulp.dest(scriptsPath)); // write to output again
+ // concat into foldername.js
+ .pipe(concat(folder + '.js'))
+ // write to output
+ .pipe(gulp.dest(scriptsPath))
+ // minify
+ .pipe(uglify())
+ // rename to folder.min.js
+ .pipe(rename(folder + '.min.js'))
+ // write to output again
+ .pipe(gulp.dest(scriptsPath));
});
// process all remaining files in scriptsPath root into main.js and main.min.js files
From b842fdf8e0477a03026efd1eb7d462fdcbda145e Mon Sep 17 00:00:00 2001
From: Blaine Bublitz
Date: Tue, 9 Feb 2016 11:56:19 -0700
Subject: [PATCH 006/216] update changelog for @code-chris - closes #1521
---
CHANGELOG.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d9846eab7..74e9767d8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# gulp changelog
+## 3.9.1
+
+- update interpret to 1.0.0 (support for babel-register)
+- fix to include manpages in published tarball
+- documentation/recipe updates
+
## 3.9.0
- add babel support
From bec9ab00e8f59c890792af8614d8d958189cc592 Mon Sep 17 00:00:00 2001
From: Alexandr Ishchenko
Date: Wed, 9 Mar 2016 18:37:53 +0300
Subject: [PATCH 007/216] Update README.md
---
docs/writing-a-plugin/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/writing-a-plugin/README.md b/docs/writing-a-plugin/README.md
index 8072d618d..e7a2c0ee9 100644
--- a/docs/writing-a-plugin/README.md
+++ b/docs/writing-a-plugin/README.md
@@ -38,7 +38,7 @@ module.exports = function() {
var error = null,
output = doSomethingWithTheFile(file);
callback(error, output);
- });
+ };
return transformStream;
};
From da47c760ce2f4d5d3ad767a587557f2cd29411fa Mon Sep 17 00:00:00 2001
From: kdex
Date: Tue, 5 Apr 2016 04:46:55 +0200
Subject: [PATCH 008/216] Add undocumented event.type
This event type is fired when renaming a file.
---
docs/API.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/API.md b/docs/API.md
index 0129f58d1..5b9fe1252 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -295,7 +295,7 @@ The callback will be passed an object, `event`, that describes the change:
##### event.type
Type: `String`
-The type of change that occurred, either `added`, `changed` or `deleted`.
+The type of change that occurred, either `added`, `changed`, `deleted` or `renamed`.
##### event.path
Type: `String`
From 5585720cbfa927f041602088d27b551659916e88 Mon Sep 17 00:00:00 2001
From: Steve Lacy
Date: Tue, 5 Apr 2016 12:37:35 -0700
Subject: [PATCH 009/216] fix links after repos were moved
---
docs/writing-a-plugin/README.md | 48 ++++++++++----------
docs/writing-a-plugin/guidelines.md | 4 +-
docs/writing-a-plugin/recommended-modules.md | 2 +-
docs/writing-a-plugin/testing.md | 4 +-
docs/writing-a-plugin/using-buffers.md | 2 +-
5 files changed, 30 insertions(+), 30 deletions(-)
diff --git a/docs/writing-a-plugin/README.md b/docs/writing-a-plugin/README.md
index e7a2c0ee9..d172b9af0 100644
--- a/docs/writing-a-plugin/README.md
+++ b/docs/writing-a-plugin/README.md
@@ -13,11 +13,11 @@ If you plan to create your own Gulp plugin, you will save time by reading the fu
A gulp plugin always returns a stream in [object mode](http://nodejs.org/api/stream.html#stream_object_mode) that does the following:
-1. Takes in [vinyl File objects](http://github.com/wearefractal/vinyl)
-2. Outputs [vinyl File objects](http://github.com/wearefractal/vinyl) (via `transform.push()` and/or the plugin's callback function)
+1. Takes in [vinyl File objects](http://github.com/gulpjs/vinyl)
+2. Outputs [vinyl File objects](http://github.com/gulpjs/vinyl) (via `transform.push()` and/or the plugin's callback function)
-These are known as [transform streams](http://nodejs.org/api/stream.html#stream_class_stream_transform_1)
-(also sometimes called through streams).
+These are known as [transform streams](http://nodejs.org/api/stream.html#stream_class_stream_transform_1)
+(also sometimes called through streams).
Transform streams are streams that are readable and writable; they manipulate objects as they're being passed through.
All gulp plugins essentially boil down to this:
@@ -25,21 +25,21 @@ All gulp plugins essentially boil down to this:
var Transform = require('transform');
module.exports = function() {
- // Monkey patch Transform or create your own subclass,
+ // Monkey patch Transform or create your own subclass,
// implementing `_transform()` and optionally `_flush()`
var transformStream = new Transform({objectMode: true});
/**
* @param {Buffer|string} file
* @param {string=} encoding - ignored if file contains a Buffer
- * @param {function(Error, object)} callback - Call this function (optionally with an
+ * @param {function(Error, object)} callback - Call this function (optionally with an
* error argument and data) when you are done processing the supplied chunk.
*/
transformStream._transform = function(file, encoding, callback) {
- var error = null,
+ var error = null,
output = doSomethingWithTheFile(file);
callback(error, output);
};
-
+
return transformStream;
};
```
@@ -59,13 +59,13 @@ module.exports = function() {
The stream returned from `through()` (and `this` within your transform function) is an instance of the [Transform](https://github.com/iojs/readable-stream/blob/master/lib/_stream_transform.js)
class, which extends [Duplex](https://github.com/iojs/readable-stream/blob/master/lib/_stream_duplex.js),
[Readable](https://github.com/iojs/readable-stream/blob/master/lib/_stream_readable.js)
-(and parasitically from Writable) and ultimately [Stream](https://nodejs.org/api/stream.html).
+(and parasitically from Writable) and ultimately [Stream](https://nodejs.org/api/stream.html).
If you need to parse additional options, you can call the `through()` function directly:
```js
return through({objectMode: true /* other options... */}, function(file, encoding, callback) { ...
```
-
+
Supported options include:
* highWaterMark (defaults to 16)
@@ -82,19 +82,19 @@ The function parameter that you pass to `through.obj()` is a [_transform](https:
function which will operate on the input `file`. You may also provide an optional [_flush](https://nodejs.org/api/stream.html#stream_transform_flush_callback)
function if you need to emit a bit more data at the end of the stream.
-From within your transform function call `this.push(file)` 0 or more times to pass along transformed/cloned files.
+From within your transform function call `this.push(file)` 0 or more times to pass along transformed/cloned files.
You don't need to call `this.push(file)` if you provide all output to the `callback()` function.
-Call the `callback` function only when the current file (stream/buffer) is completely consumed.
-If an error is encountered, pass it as the first argument to the callback, otherwise set it to null.
+Call the `callback` function only when the current file (stream/buffer) is completely consumed.
+If an error is encountered, pass it as the first argument to the callback, otherwise set it to null.
If you have passed all output data to `this.push()` you can omit the second argument to the callback.
Generally, a gulp plugin would update `file.contents` and then choose to either:
- - call `callback(null, file)`
- _or_
+ - call `callback(null, file)`
+ _or_
- make one call to `this.push(file)`
-
+
If a plugin creates multiple files from a single input file, it would make multiple calls to `this.push()` - eg:
```js
@@ -105,10 +105,10 @@ module.exports = function() {
var transform = function(file, encoding, callback) {
var files = splitFile(file);
this.push(files[0]);
- this.push(files[1]);
+ this.push(files[1]);
callback();
- };
-
+ };
+
return through.obj(transform);
};
```
@@ -141,14 +141,14 @@ module.exports = function() {
if (file.isStream()) {
// file.contents is a Stream - https://nodejs.org/api/stream.html
this.emit('error', new PluginError(PLUGIN_NAME, 'Streams not supported!'));
-
+
// or, if you can handle Streams:
//file.contents = file.contents.pipe(...
//return callback(null, file);
} else if (file.isBuffer()) {
// file.contents is a Buffer - https://nodejs.org/api/buffer.html
this.emit('error', new PluginError(PLUGIN_NAME, 'Buffers not supported!'));
-
+
// or, if you can handle Buffers:
//file.contents = ...
//return callback(null, file);
@@ -176,17 +176,17 @@ if (someCondition) {
## Useful resources
-* [File object](https://github.com/wearefractal/gulp-util/#new-fileobj)
+* [File object](https://github.com/gulpjs/gulp-util/#new-fileobj)
* [PluginError](https://github.com/gulpjs/gulp-util#new-pluginerrorpluginname-message-options)
* [event-stream](https://github.com/dominictarr/event-stream)
* [BufferStream](https://github.com/nfroidure/BufferStream)
-* [gulp-util](https://github.com/wearefractal/gulp-util)
+* [gulp-util](https://github.com/gulpjs/gulp-util)
## Sample plugins
* [sindresorhus' gulp plugins](https://github.com/search?q=%40sindresorhus+gulp-)
-* [Fractal's gulp plugins](https://github.com/search?q=%40wearefractal+gulp-)
+* [contra's gulp plugins](https://github.com/search?q=%40contra+gulp-)
* [gulp-replace](https://github.com/lazd/gulp-replace)
diff --git a/docs/writing-a-plugin/guidelines.md b/docs/writing-a-plugin/guidelines.md
index 014bff1fb..158b1f80b 100644
--- a/docs/writing-a-plugin/guidelines.md
+++ b/docs/writing-a-plugin/guidelines.md
@@ -13,7 +13,7 @@
- Avoid config options that make your plugin do completely different tasks
- For example: A JS minification plugin should not have an option that adds a header as well
1. Your plugin shouldn't do things that other plugins are responsible for
- - It should not concat, [gulp-concat](https://github.com/wearefractal/gulp-concat) does that
+ - It should not concat, [gulp-concat](https://github.com/contra/gulp-concat) does that
- It should not add headers, [gulp-header](https://github.com/godaddy/gulp-header) does that
- It should not add footers, [gulp-footer](https://github.com/godaddy/gulp-footer) does that
- If it's a common but optional use case, document that your plugin is often used with another plugin
@@ -35,7 +35,7 @@
- If file.contents is a Stream and you don't support that just emit an error
- Do not buffer a stream to shoehorn your plugin to work with streams. This will cause horrible things to happen.
1. Do not pass the `file` object downstream until you are done with it
-1. Use [`file.clone()`](https://github.com/wearefractal/vinyl#clone) when cloning a file or creating a new one based on a file.
+1. Use [`file.clone()`](https://github.com/gulpjs/vinyl#clone) when cloning a file or creating a new one based on a file.
1. Use modules from our [recommended modules page](recommended-modules.md) to make your life easier
1. Do NOT require `gulp` as a dependency or peerDependency in your plugin
- Using gulp to test or automate your plugin workflow is totally cool, just make sure you put it as a devDependency
diff --git a/docs/writing-a-plugin/recommended-modules.md b/docs/writing-a-plugin/recommended-modules.md
index 4e027e7cf..ca1d7e71b 100644
--- a/docs/writing-a-plugin/recommended-modules.md
+++ b/docs/writing-a-plugin/recommended-modules.md
@@ -10,7 +10,7 @@ Use [replace-ext](https://github.com/wearefractal/replace-ext)
#### Errors
-Use [BetterError](https://github.com/wearefractal/BetterError) when it is finished
+Use [BetterError](https://github.com/contra/BetterError) when it is finished
#### String colors
diff --git a/docs/writing-a-plugin/testing.md b/docs/writing-a-plugin/testing.md
index 573d8c64a..487a87f95 100644
--- a/docs/writing-a-plugin/testing.md
+++ b/docs/writing-a-plugin/testing.md
@@ -94,8 +94,8 @@ describe('gulp-prefixer', function() {
});
```
-
+
## Some plugins with high-quality Testing
* [gulp-cat](https://github.com/ben-eb/gulp-cat/blob/master/test.js)
-* [gulp-concat](https://github.com/wearefractal/gulp-concat/blob/master/test/main.js)
+* [gulp-concat](https://github.com/contra/gulp-concat/blob/master/test/main.js)
diff --git a/docs/writing-a-plugin/using-buffers.md b/docs/writing-a-plugin/using-buffers.md
index ff58b1eb7..ae021448b 100644
--- a/docs/writing-a-plugin/using-buffers.md
+++ b/docs/writing-a-plugin/using-buffers.md
@@ -66,7 +66,7 @@ Unfortunately, the above plugin will error when using gulp.src in non-buffered (
## Some plugins based on buffers
-* [gulp-coffee](https://github.com/wearefractal/gulp-coffee)
+* [gulp-coffee](https://github.com/contra/gulp-coffee)
* [gulp-svgmin](https://github.com/ben-eb/gulp-svgmin)
* [gulp-marked](https://github.com/lmtm/gulp-marked)
* [gulp-svg2ttf](https://github.com/nfroidure/gulp-svg2ttf)
From e90e289d872c58180df3e5e7a026c9dd187c62f8 Mon Sep 17 00:00:00 2001
From: Christian Theilemann
Date: Tue, 5 Apr 2016 13:12:08 -0700
Subject: [PATCH 010/216] add `run-grunt-tasks-from-gulp` recipe
---
docs/recipes/run-grunt-tasks-from-gulp.md | 48 +++++++++++++++++++++++
1 file changed, 48 insertions(+)
create mode 100644 docs/recipes/run-grunt-tasks-from-gulp.md
diff --git a/docs/recipes/run-grunt-tasks-from-gulp.md b/docs/recipes/run-grunt-tasks-from-gulp.md
new file mode 100644
index 000000000..80e54a448
--- /dev/null
+++ b/docs/recipes/run-grunt-tasks-from-gulp.md
@@ -0,0 +1,48 @@
+# Run Grunt Tasks from Gulp
+
+It is possible to run Grunt tasks / Grunt plugins from within Gulp. This can be useful during a gradual migration from Grunt to Gulp or if there's a specific plugin that you need. With the described approach no Grunt CLI and no Gruntfile is required.
+
+**This approach requires Grunt >=1.0.0**
+
+very simple example `gulpfile.js`:
+
+```js
+// npm install gulp grunt grunt-contrib-copy --save-dev
+
+var gulp = require('gulp');
+var grunt = require('grunt');
+
+grunt.initConfig({
+ copy: {
+ main: {
+ src: 'src/*',
+ dest: 'dest/'
+ }
+ }
+});
+grunt.loadNpmTasks('grunt-contrib-copy');
+
+gulp.task('copy', function (done) {
+ grunt.tasks(
+ ['copy:main'], //you can add more grunt tasks in this array
+ {gruntfile: false}, //don't look for a Gruntfile - there is none. :-)
+ function () {done();}
+ );
+});
+
+```
+
+Now start the task with:
+`gulp copy`
+
+With the aforementioned approach the grunt tasks get registered within gulp's task system. **Keep in mind grunt tasks are usually blocking (unlike gulp), therefore no other task (not even a gulp task) can run until a grunt task is completed.**
+
+
+### A few words on alternatives
+
+There's a *gulpfriendly* node module `gulp-grunt` [available](https://www.npmjs.org/package/gulp-grunt) which takes a different approach. It spawns child processes and within them the grunt tasks are executed. The way it works implies some limitations though:
+
+* It is at the moment not possible to pass options / cli args etc. to the grunt tasks via `gulp-grunt`
+* All grunt tasks have to be defined in a seperate Gruntfile
+* You need to have the Grunt CLI installed
+* The output of some grunt tasks gets malformatted (.i.e. color coding).
From 55dec395fc52b27f78aab5928def2c1048f0010c Mon Sep 17 00:00:00 2001
From: Steve Lacy
Date: Wed, 6 Apr 2016 16:58:47 -0700
Subject: [PATCH 011/216] fix remaining links + add missing link to recipe
---
docs/API.md | 16 ++++++++--------
docs/recipes/README.md | 1 +
docs/recipes/specifying-a-cwd.md | 2 +-
3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/docs/API.md b/docs/API.md
index 5b9fe1252..0c03c2e3f 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -8,9 +8,9 @@ Jump to:
### gulp.src(globs[, options])
-Emits files matching provided glob or an array of globs.
-Returns a [stream](http://nodejs.org/api/stream.html) of [Vinyl files](https://github.com/wearefractal/vinyl-fs)
-that can be [piped](http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options)
+Emits files matching provided glob or an array of globs.
+Returns a [stream](http://nodejs.org/api/stream.html) of [Vinyl files](https://github.com/gulpjs/vinyl-fs)
+that can be [piped](http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options)
to plugins.
```javascript
@@ -35,7 +35,7 @@ A glob that begins with `!` excludes matching files from the glob results up to
The following expression matches `a.js` and `bad.js`:
gulp.src(['client/*.js', '!client/b*.js', 'client/bad.js'])
-
+
#### options
Type: `Object`
@@ -85,13 +85,13 @@ gulp.src('./client/templates/*.jade')
```
The write path is calculated by appending the file relative path to the given
-destination directory. In turn, relative paths are calculated against the file base.
+destination directory. In turn, relative paths are calculated against the file base.
See `gulp.src` above for more info.
#### path
Type: `String` or `Function`
-The path (output folder) to write files to. Or a function that returns it, the function will be provided a [vinyl File instance](https://github.com/wearefractal/vinyl).
+The path (output folder) to write files to. Or a function that returns it, the function will be provided a [vinyl File instance](https://github.com/gulpjs/vinyl).
#### options
Type: `Object`
@@ -156,7 +156,7 @@ gulp.task('buildStuff', function() {
.pipe(somePlugin())
.pipe(someOtherPlugin())
.pipe(gulp.dest(/*some destination*/));
-
+
return stream;
});
```
@@ -306,7 +306,7 @@ The path to the file that triggered the event.
[node-glob]: https://github.com/isaacs/node-glob
[node-glob documentation]: https://github.com/isaacs/node-glob#options
[node-glob syntax]: https://github.com/isaacs/node-glob
-[glob-stream]: https://github.com/wearefractal/glob-stream
+[glob-stream]: https://github.com/gulpjs/glob-stream
[gulp-if]: https://github.com/robrich/gulp-if
[Orchestrator]: https://github.com/robrich/orchestrator
[glob2base]: https://github.com/wearefractal/glob2base
diff --git a/docs/recipes/README.md b/docs/recipes/README.md
index a2b79be07..9e8124bc7 100644
--- a/docs/recipes/README.md
+++ b/docs/recipes/README.md
@@ -23,4 +23,5 @@
* [Browserify + Globs (multiple destination)](browserify-multiple-destination.md)
* [Output both a minified and non-minified version](minified-and-non-minified.md)
* [Templating with Swig and YAML front-matter](templating-with-swig-and-yaml-front-matter.md)
+* [Run Grunt Tasks from Gulp](run-grunt-tasks-from-gulp.md)
* [Exports as tasks](exports-as-tasks.md)
diff --git a/docs/recipes/specifying-a-cwd.md b/docs/recipes/specifying-a-cwd.md
index d3858fcd7..eba0ceca9 100644
--- a/docs/recipes/specifying-a-cwd.md
+++ b/docs/recipes/specifying-a-cwd.md
@@ -16,7 +16,7 @@ From the `project/` directory:
gulp --cwd layer1
```
-If you only need to specify a cwd for a certain glob, you can use the `cwd` option on a [glob-stream](https://github.com/wearefractal/glob-stream):
+If you only need to specify a cwd for a certain glob, you can use the `cwd` option on a [glob-stream](https://github.com/gulpjs/glob-stream):
```js
gulp.src('./some/dir/**/*.js', { cwd: 'public' });
From b2915d7fa094475e42bf0400dacd0070029051c8 Mon Sep 17 00:00:00 2001
From: Andrew Smith
Date: Fri, 8 Apr 2016 12:34:05 -0700
Subject: [PATCH 012/216] Surface 'on' listener functionality (#1424)
* Surface 'on' listener functionality
* change to fit with existing structure of examples
---
docs/API.md | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/docs/API.md b/docs/API.md
index 0c03c2e3f..4bb90bbe8 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -177,6 +177,17 @@ gulp.task('jekyll', function(cb) {
cb(); // finished task
});
});
+
+// use an async result in a pipe
+gulp.task('somename', function(cb) {
+ getFilesAsync(function(err, res) {
+ if (err) return cb(err);
+ var stream = gulp.src(res)
+ .pipe(minify())
+ .pipe(gulp.dest('build'))
+ .on('end', cb);
+ });
+});
```
##### Return a stream
From 9f1b90f7c1c16be8aef9f290576aedbb66e1548a Mon Sep 17 00:00:00 2001
From: Slava Fomin
Date: Fri, 8 Apr 2016 22:35:31 +0300
Subject: [PATCH 013/216] =?UTF-8?q?Updated=20=C2=ABSplit=20tasks=20across?=
=?UTF-8?q?=20multiple=20files=C2=BB=20recipe=20(#1585)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Updated «Split tasks across multiple files» recipe.
* Added deprecation notice.
---
.../split-tasks-across-multiple-files.md | 25 ++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/docs/recipes/split-tasks-across-multiple-files.md b/docs/recipes/split-tasks-across-multiple-files.md
index 023891976..fb820ad1d 100644
--- a/docs/recipes/split-tasks-across-multiple-files.md
+++ b/docs/recipes/split-tasks-across-multiple-files.md
@@ -1,8 +1,22 @@
# Split tasks across multiple files
-If your `gulpfile.js` is starting to grow too large, you can split the tasks
-into separate files by using the [require-dir](https://github.com/aseemk/requireDir)
-module.
+If your `gulpfile.js` is starting to grow too large, you can split
+the tasks into separate files using one of the methods below.
+
+> Be advised, that this approach is [considered deprecated][deprecated]
+> and could lead to problems when migrating to the `gulp 4`.
+
+
+## Using `gulp-require-tasks`
+
+You can use the [gulp-require-tasks][gulp-require-tasks]
+module to automatically load all your tasks from the individual files.
+
+Please see the [module's README][gulp-require-tasks] for up-to-date instructions.
+
+## Using `require-dir`
+
+You can also use the [require-dir][require-dir] module to load your tasks manually.
Imagine the following file structure:
@@ -26,3 +40,8 @@ Add the following lines to your `gulpfile.js` file:
var requireDir = require('require-dir');
var tasks = requireDir('./tasks');
```
+
+
+ [gulp-require-tasks]: https://github.com/betsol/gulp-require-tasks
+ [require-dir]: https://github.com/aseemk/requireDir
+ [deprecated]: https://github.com/gulpjs/gulp/pull/1554#issuecomment-202614391
From db86eedc1a7ae306ec0813e4d554b95a930ecea9 Mon Sep 17 00:00:00 2001
From: Adrian Sieber
Date: Wed, 13 Apr 2016 18:46:39 +0000
Subject: [PATCH 014/216] Fix typos
---
docs/recipes/run-grunt-tasks-from-gulp.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/recipes/run-grunt-tasks-from-gulp.md b/docs/recipes/run-grunt-tasks-from-gulp.md
index 80e54a448..cdd4f6861 100644
--- a/docs/recipes/run-grunt-tasks-from-gulp.md
+++ b/docs/recipes/run-grunt-tasks-from-gulp.md
@@ -43,6 +43,6 @@ With the aforementioned approach the grunt tasks get registered within gulp's ta
There's a *gulpfriendly* node module `gulp-grunt` [available](https://www.npmjs.org/package/gulp-grunt) which takes a different approach. It spawns child processes and within them the grunt tasks are executed. The way it works implies some limitations though:
* It is at the moment not possible to pass options / cli args etc. to the grunt tasks via `gulp-grunt`
-* All grunt tasks have to be defined in a seperate Gruntfile
+* All grunt tasks have to be defined in a separate Gruntfile
* You need to have the Grunt CLI installed
* The output of some grunt tasks gets malformatted (.i.e. color coding).
From 2395467ed4e4942b24763f421177eab683924bfe Mon Sep 17 00:00:00 2001
From: dargaCode
Date: Mon, 25 Apr 2016 14:01:30 -0700
Subject: [PATCH 015/216] Fix small typo (#1612)
Replace `it's` with `its`
---
docs/recipes/browserify-with-globs.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/recipes/browserify-with-globs.md b/docs/recipes/browserify-with-globs.md
index 0285c1f5e..ad7df6f83 100644
--- a/docs/recipes/browserify-with-globs.md
+++ b/docs/recipes/browserify-with-globs.md
@@ -1,6 +1,6 @@
# Browserify + Globs
-[Browserify + Uglify2](https://github.com/gulpjs/gulp/blob/master/docs/recipes/browserify-uglify-sourcemap.md) shows how to setup a basic gulp task to bundle a JavaScript file with it's dependencies, and minify the bundle with UglifyJS while preserving source maps.
+[Browserify + Uglify2](https://github.com/gulpjs/gulp/blob/master/docs/recipes/browserify-uglify-sourcemap.md) shows how to setup a basic gulp task to bundle a JavaScript file with its dependencies, and minify the bundle with UglifyJS while preserving source maps.
It does not, however, show how one may use gulp and Browserify with multiple entry files.
See also: the [Combining Streams to Handle Errors](https://github.com/gulpjs/gulp/blob/master/docs/recipes/combining-streams-to-handle-errors.md) recipe for handling errors with Browserify or UglifyJS in your stream.
From 02fe60fe14cf37c213ef79b2c48e4382aae6e7ee Mon Sep 17 00:00:00 2001
From: Jaron Thatcher
Date: Wed, 27 Apr 2016 15:25:02 -0700
Subject: [PATCH 016/216] Bottom example is now runnable (#1615)
* Bottom example is now runnable
Previously, the app would throw the error:
"Task 'default' is not in your gulpfile"
* Revert change to glob
The change is now closer to the original example, yet still contains the intended reason for the pull request
---
docs/recipes/mocha-test-runner-with-gulp.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/docs/recipes/mocha-test-runner-with-gulp.md b/docs/recipes/mocha-test-runner-with-gulp.md
index d7cd96e48..69788aad8 100644
--- a/docs/recipes/mocha-test-runner-with-gulp.md
+++ b/docs/recipes/mocha-test-runner-with-gulp.md
@@ -28,13 +28,13 @@ var gulp = require('gulp');
var mocha = require('gulp-mocha');
var gutil = require('gulp-util');
+gulp.task('default', function() {
+ gulp.watch(['lib/**', 'test/**'], ['mocha']);
+});
+
gulp.task('mocha', function() {
return gulp.src(['test/*.js'], { read: false })
.pipe(mocha({ reporter: 'list' }))
.on('error', gutil.log);
});
-
-gulp.task('watch-mocha', function() {
- gulp.watch(['lib/**', 'test/**'], ['mocha']);
-});
```
From 7f5ac012315fca6a3ad8105b6f50e8143b237c94 Mon Sep 17 00:00:00 2001
From: Jonathan Lee
Date: Tue, 3 May 2016 16:23:16 -0400
Subject: [PATCH 017/216] #1445 - adding note to let folks know this only works
with the latest published gulp-cli version (#1632)
---
docs/recipes/exports-as-tasks.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/docs/recipes/exports-as-tasks.md b/docs/recipes/exports-as-tasks.md
index 5ea06fd44..2eaea4905 100644
--- a/docs/recipes/exports-as-tasks.md
+++ b/docs/recipes/exports-as-tasks.md
@@ -18,3 +18,5 @@ export default function dev() {
gulp.watch('src/*.js', ['build']);
}
```
+
+This will **not** work with the gulp-cli version bundled with gulp 3.x. You must use the latest published version.
From 5944c1b4d4c0a9dea804bc426b936aa742792cd4 Mon Sep 17 00:00:00 2001
From: mako yass
Date: Sat, 14 May 2016 06:50:29 +1200
Subject: [PATCH 018/216] correct gulp.task signature (#1653)
* correct gulp.task signature
`gulp.task(name [, deps, fn])` means that only `gulp.task(name, deps, fn)` and `gulp.task(name)` are allowed, which is apparently not the case and it's a bit confusing. The correct notation, `gulp.task(name [, deps] [, fn])`, also permits for `gulp.task(name, deps)`, and `gulp.task(name, fn)`.
* fixed indexing
---
docs/API.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/API.md b/docs/API.md
index 4bb90bbe8..d06906f13 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -3,7 +3,7 @@
Jump to:
[gulp.src](#gulpsrcglobs-options) |
[gulp.dest](#gulpdestpath-options) |
- [gulp.task](#gulptaskname--deps-fn) |
+ [gulp.task](#gulptaskname--deps--fn) |
[gulp.watch](#gulpwatchglob--opts-tasks-or-gulpwatchglob--opts-cb)
### gulp.src(globs[, options])
@@ -108,7 +108,7 @@ Default: `0777`
Octal permission string specifying mode for any folders that need to be created for output folder.
-### gulp.task(name [, deps, fn])
+### gulp.task(name [, deps] [, fn])
Define a task using [Orchestrator].
From f6e85a85ad4e7253dbd179ac6195c9b2ae59baa9 Mon Sep 17 00:00:00 2001
From: Alejandro Oviedo
Date: Tue, 17 May 2016 15:26:36 -0300
Subject: [PATCH 019/216] link build badge to master branch (#1666)
...and change gitter image badge to svg
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index b67798c75..db07c9ef0 100644
--- a/README.md
+++ b/README.md
@@ -94,10 +94,10 @@ Anyone can help make this project better - check out our [Contributing guide](/C
[npm-image]: https://img.shields.io/npm/v/gulp.svg
[travis-url]: https://travis-ci.org/gulpjs/gulp
-[travis-image]: https://img.shields.io/travis/gulpjs/gulp.svg
+[travis-image]: https://img.shields.io/travis/gulpjs/gulp/master.svg
[coveralls-url]: https://coveralls.io/r/gulpjs/gulp
[coveralls-image]: https://img.shields.io/coveralls/gulpjs/gulp/master.svg
[gitter-url]: https://gitter.im/gulpjs/gulp
-[gitter-image]: https://badges.gitter.im/gulpjs/gulp.png
+[gitter-image]: https://badges.gitter.im/gulpjs/gulp.svg
From 4ec7e71f39fe8ab3c95b81b3266317366252e8e7 Mon Sep 17 00:00:00 2001
From: Trey Thomas
Date: Thu, 19 May 2016 13:36:47 -0600
Subject: [PATCH 020/216] Fix typo in README.md (#1670)
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index db07c9ef0..713bc5e8d 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@
## Documentation
-For a Getting started guide, API docs, recipes, making a plugin, etc. check out or docs!
+For a Getting started guide, API docs, recipes, making a plugin, etc. check out our docs!
- Need something reliable? Check out the [documentation for the current release](/docs/README.md)!
- Want to help us test the latest and greatest? Check out the [documentation for the next release](https://github.com/gulpjs/gulp/tree/4.0)!
From 362306150fc5be48a61df0d950c83cca356bd593 Mon Sep 17 00:00:00 2001
From: MikailBag
Date: Sun, 19 Jun 2016 04:57:52 +0300
Subject: [PATCH 021/216] Build: CI test under node version 5 and 6 (#1692)
---
.travis.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index b60f49053..5d5228b1e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,7 +4,8 @@ node_js:
- "0.10"
- "0.12"
- "4"
- - "stable"
+ - "5"
+ - "6"
after_script:
- npm run coveralls
git:
From b42acd91ae5785c88d37218787f0d85089e8f705 Mon Sep 17 00:00:00 2001
From: Permutator
Date: Sat, 18 Jun 2016 20:31:42 -0700
Subject: [PATCH 022/216] Docs: Add "Rollup with rollup-stream" recipe. (#1690)
---
docs/recipes/README.md | 1 +
docs/recipes/rollup-with-rollup-stream.md | 62 +++++++++++++++++++++++
2 files changed, 63 insertions(+)
create mode 100644 docs/recipes/rollup-with-rollup-stream.md
diff --git a/docs/recipes/README.md b/docs/recipes/README.md
index 9e8124bc7..b532750ae 100644
--- a/docs/recipes/README.md
+++ b/docs/recipes/README.md
@@ -25,3 +25,4 @@
* [Templating with Swig and YAML front-matter](templating-with-swig-and-yaml-front-matter.md)
* [Run Grunt Tasks from Gulp](run-grunt-tasks-from-gulp.md)
* [Exports as tasks](exports-as-tasks.md)
+* [Rollup with rollup-stream](rollup-with-rollup-stream.md)
diff --git a/docs/recipes/rollup-with-rollup-stream.md b/docs/recipes/rollup-with-rollup-stream.md
new file mode 100644
index 000000000..abee2dd32
--- /dev/null
+++ b/docs/recipes/rollup-with-rollup-stream.md
@@ -0,0 +1,62 @@
+# Rollup with rollup-stream
+
+Like Browserify, [Rollup](http://rollupjs.org/) is a bundler and thus only fits naturally into gulp if it's at the start of the pipeline. Unlike Browserify, Rollup doesn't natively produce a stream as output and needs to be wrapped before it can take this position. [rollup-stream](https://github.com/Permutatrix/rollup-stream) does this for you, producing output just like that of Browserify's `bundle()` method—as a result, most of the Browserify recipes here will also work with rollup-stream.
+
+## Basic usage
+```js
+// npm install --save-dev rollup-stream vinyl-source-stream
+var gulp = require('gulp');
+var rollup = require('rollup-stream');
+var source = require('vinyl-source-stream');
+
+gulp.task('rollup', function() {
+ return rollup({
+ entry: './src/main.js'
+ })
+
+ // give the file the name you want to output with
+ .pipe(source('app.js'))
+
+ // and output to ./dist/app.js as normal.
+ .pipe(gulp.dest('./dist'));
+});
+```
+
+## Usage with sourcemaps
+```js
+// npm install --save-dev rollup-stream gulp-sourcemaps vinyl-source-stream vinyl-buffer
+// optional: npm install --save-dev gulp-rename
+var gulp = require('gulp');
+var rollup = require('rollup-stream');
+var sourcemaps = require('gulp-sourcemaps');
+//var rename = require('gulp-rename');
+var source = require('vinyl-source-stream');
+var buffer = require('vinyl-buffer');
+
+gulp.task('rollup', function() {
+ return rollup({
+ entry: './src/main.js',
+ sourceMap: true
+ })
+
+ // point to the entry file.
+ .pipe(source('main.js', './src'))
+
+ // buffer the output. most gulp plugins, including gulp-sourcemaps, don't support streams.
+ .pipe(buffer())
+
+ // tell gulp-sourcemaps to load the inline sourcemap produced by rollup-stream.
+ .pipe(sourcemaps.init({loadMaps: true}))
+
+ // transform the code further here.
+
+ // if you want to output with a different name from the input file, use gulp-rename here.
+ //.pipe(rename('index.js'))
+
+ // write the sourcemap alongside the output file.
+ .pipe(sourcemaps.write('.'))
+
+ // and output to ./dist/main.js as normal.
+ .pipe(gulp.dest('./dist'));
+});
+```
From 71953b58ee8077ee882272d1834e3f0ded9a2b92 Mon Sep 17 00:00:00 2001
From: Cerem Cem ASLAN
Date: Wed, 29 Jun 2016 00:43:14 +0300
Subject: [PATCH 023/216] Docs: Add npm init step to Getting Started (#1706)
---
docs/getting-started.md | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/docs/getting-started.md b/docs/getting-started.md
index ef23c5945..cb3ecf553 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -9,13 +9,19 @@ to make sure your old version doesn't collide with gulp-cli.__
$ npm install --global gulp-cli
```
-#### 2. Install gulp in your project devDependencies:
+#### 2. Initialize your project directory:
+
+```sh
+$ npm init
+```
+
+#### 3. Install gulp in your project devDependencies:
```sh
$ npm install --save-dev gulp
```
-#### 3. Create a `gulpfile.js` at the root of your project:
+#### 4. Create a `gulpfile.js` at the root of your project:
```js
var gulp = require('gulp');
@@ -25,7 +31,7 @@ gulp.task('default', function() {
});
```
-#### 4. Run gulp:
+#### 5. Run gulp:
```sh
$ gulp
From 347ed5a731fe4b479d72c35d38503680621c316a Mon Sep 17 00:00:00 2001
From: Pia Mancini
Date: Thu, 30 Jun 2016 15:06:53 -0600
Subject: [PATCH 024/216] Docs: Add backers and sponsors from OpenCollective
(#1705)
Your open collective backers & sponsors will show up on your readme automatically. Also added badges on top.
---
README.md | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 713bc5e8d..3789d085f 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,8 @@
The streaming build system
-[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Coveralls Status][coveralls-image]][coveralls-url] [![Gitter chat][gitter-image]][gitter-url]
+[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Coveralls Status][coveralls-image]][coveralls-url] [![OpenCollective Backers][backer-badge]][backer-url] [![OpenCollective Sponsors][sponsor-badge]][sponsor-url] [![Gitter chat][gitter-image]][gitter-url]
+
## What is gulp?
@@ -89,6 +90,18 @@ We recommend these plugins:
Anyone can help make this project better - check out our [Contributing guide](/CONTRIBUTING.md)!
+## Backers
+
+Support us with a monthly donation and help us continue our activities.
+
+[![Backers][backers-image]][support-url]
+
+## Sponsors
+
+Become a sponsor to get your logo on our README on Github.
+
+[![Sponsors][sponsors-image]][support-url]
+
[downloads-image]: https://img.shields.io/npm/dm/gulp.svg
[npm-url]: https://www.npmjs.com/package/gulp
[npm-image]: https://img.shields.io/npm/v/gulp.svg
@@ -101,3 +114,13 @@ Anyone can help make this project better - check out our [Contributing guide](/C
[gitter-url]: https://gitter.im/gulpjs/gulp
[gitter-image]: https://badges.gitter.im/gulpjs/gulp.svg
+
+[backer-url]: #backers
+[backer-badge]: https://opencollective.com/gulpjs/backers/badge.svg?color=blue
+[sponsor-url]: #sponsors
+[sponsor-badge]: https://opencollective.com/gulpjs/sponsors/badge.svg?color=blue
+
+[support-url]: https://opencollective.com/gulpjs#support
+
+[backers-image]: https://opencollective.com/gulpjs/backers.svg
+[sponsors-image]: https://opencollective.com/gulpjs/sponsors.svg
From de1acf66a6253302c856971f8c00f65ea6c63882 Mon Sep 17 00:00:00 2001
From: Derek
Date: Fri, 26 Aug 2016 11:20:50 -0700
Subject: [PATCH 025/216] Docs: Fix grammar in dealing-with-streams.md
---
docs/writing-a-plugin/dealing-with-streams.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/writing-a-plugin/dealing-with-streams.md b/docs/writing-a-plugin/dealing-with-streams.md
index ae74dda3b..4c6d53830 100644
--- a/docs/writing-a-plugin/dealing-with-streams.md
+++ b/docs/writing-a-plugin/dealing-with-streams.md
@@ -2,7 +2,7 @@
> It is highly recommended to write plugins supporting streams. Here is some information on creating a gulp plugin that supports streams.
-> Make sure to follow the best practice regarding error handling and add the line that make the gulp plugin re-emit the first error caught during the transformation of the content
+> Make sure to follow the best practices regarding error handling and add a line that makes the gulp plugin re-emit the first error caught during the transformation of the content.
[Writing a Plugin](README.md) > Writing stream based plugins
From 4d1a8a8a86127441ce9a94e9d34f7587fddae389 Mon Sep 17 00:00:00 2001
From: Callum Macrae
Date: Fri, 16 Sep 2016 10:46:39 +0100
Subject: [PATCH 026/216] Docs: Create issue template to cover common issues
(#1808)
---
.github/ISSUE_TEMPLATE.md | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 .github/ISSUE_TEMPLATE.md
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 000000000..1ec2c2c73
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,28 @@
+This tracker is for bug reports only.
+
+
+Before opening an issue, please make sure you've checked the following:
+
+- For support requests, please use Stack Overflow (stackoverflow.com) or Gitter (see the README).
+
+- If the bug is in a plugin, open an issue on the plugin repository, not the gulp repository.
+
+- If you're getting a deprecated module warning, don't worry about it: we're aware of it and it's not an issue. To make it go away, update to Gulp 4.0.
+
+- If you're asking about the status of Gulp 4, please don't! You can see the remaining issues on the gulp4 label: https://github.com/gulpjs/gulp/issues?q=is%3Aissue+is%3Aopen+label%3Agulp4
+
+----
+
+**What were you expecting to happen?**
+
+**What actually happened?**
+
+**Please post a sample of your gulpfile (preferably reduced to just the bit that's not working)**
+
+```js
+gulp.task(function () {});
+```
+
+**What version of gulp are you using?**
+
+**What versions of npm and node are you using?**
From 0469094bb8c4c54e5bb8b2cf5994dd72fa8db713 Mon Sep 17 00:00:00 2001
From: contra
Date: Wed, 21 Sep 2016 12:07:51 -0400
Subject: [PATCH 027/216] clarify what an API should look like
---
docs/writing-a-plugin/guidelines.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/docs/writing-a-plugin/guidelines.md b/docs/writing-a-plugin/guidelines.md
index 158b1f80b..79cb3e703 100644
--- a/docs/writing-a-plugin/guidelines.md
+++ b/docs/writing-a-plugin/guidelines.md
@@ -22,6 +22,9 @@
- Testing a gulp plugin is easy, you don't even need gulp to test it
- Look at other plugins for examples
1. Add `gulpplugin` as a keyword in your `package.json` so you show up on our search
+1. Your plugin API should be a function that returns a stream
+ - If you need to store state somewhere, do it internally
+ - If you need to pass state/options between plugins, tack it on the file object
1. Do not throw errors inside a stream
- Instead, you should emit it as an **error** event.
- If you encounter an error **outside** the stream, such as invalid configuration while creating the stream, you may throw it.
From 54169eb802228f810e77602b4131be1a2a5e6506 Mon Sep 17 00:00:00 2001
From: Ben Halverson
Date: Mon, 7 Nov 2016 19:25:36 -0800
Subject: [PATCH 028/216] Docs: Fix broken gulp-header/gulp-footer links
(closes #1851) (#1854)
---
docs/writing-a-plugin/guidelines.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/writing-a-plugin/guidelines.md b/docs/writing-a-plugin/guidelines.md
index 79cb3e703..4c924574c 100644
--- a/docs/writing-a-plugin/guidelines.md
+++ b/docs/writing-a-plugin/guidelines.md
@@ -14,8 +14,8 @@
- For example: A JS minification plugin should not have an option that adds a header as well
1. Your plugin shouldn't do things that other plugins are responsible for
- It should not concat, [gulp-concat](https://github.com/contra/gulp-concat) does that
- - It should not add headers, [gulp-header](https://github.com/godaddy/gulp-header) does that
- - It should not add footers, [gulp-footer](https://github.com/godaddy/gulp-footer) does that
+ - It should not add headers, [gulp-header](https://www.npmjs.com/package/gulp-header) does that
+ - It should not add footers, [gulp-footer](https://www.npmjs.com/package/gulp-footer) does that
- If it's a common but optional use case, document that your plugin is often used with another plugin
- Make use of other plugins within your plugin! This reduces the amount of code you have to write and ensures a stable ecosystem.
1. Your plugin **must be tested**
From af33d4b8eaf393854499c0b20ad607c6a1346844 Mon Sep 17 00:00:00 2001
From: Bruno Belotti
Date: Tue, 13 Dec 2016 11:45:56 +0000
Subject: [PATCH 029/216] fix link to tagtree video (#1869)
tagtree.io instead of tagtree.tv
---
docs/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/README.md b/docs/README.md
index 0a7e40897..fbcef8bcd 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -29,7 +29,7 @@ Post on [StackOverflow with a #gulp tag](http://stackoverflow.com/questions/tagg
## Articles
-* [Tagtree intro to gulp video](http://tagtree.tv/gulp)
+* [Tagtree intro to gulp video](http://tagtree.io/gulp)
* [Introduction to node.js streams](https://github.com/substack/stream-handbook)
* [Video introduction to node.js streams](http://www.youtube.com/watch?v=QgEuZ52OZtU)
* [Getting started with gulp (by @markgdyr)](http://markgoodyear.com/2014/01/getting-started-with-gulp/)
From 6899a6c94ce662e9bdcb3e82f39d3c78138e4c3c Mon Sep 17 00:00:00 2001
From: Mohammad Kermani
Date: Thu, 15 Dec 2016 01:28:10 +0330
Subject: [PATCH 030/216] Docs: Update browserify-uglify-sourcemap recipe with
clarification (#1813)
---
docs/recipes/browserify-uglify-sourcemap.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/docs/recipes/browserify-uglify-sourcemap.md b/docs/recipes/browserify-uglify-sourcemap.md
index 467792023..756b89ac3 100644
--- a/docs/recipes/browserify-uglify-sourcemap.md
+++ b/docs/recipes/browserify-uglify-sourcemap.md
@@ -4,7 +4,9 @@
tool but requires being wrapped before working well with gulp. Below is a simple recipe for using
Browserify with full sourcemaps that resolve to the original individual files.
-See also: the [Combining Streams to Handle Errors](https://github.com/gulpjs/gulp/blob/master/docs/recipes/combining-streams-to-handle-errors.md) recipe for handling errors with browserify or uglify in your stream.
+See also: the [Combining Streams to Handle Errors](https://github.com/gulpjs/gulp/blob/master/docs/recipes/combining-streams-to-handle-errors.md) recipe for handling errors with browserify or uglify in your stream.
+
+A simple `gulpfile.js` file for Browserify + Uglify2 with sourcemaps:
``` javascript
'use strict';
From 9703acac2b1387e3f23d227ef739443bb6539709 Mon Sep 17 00:00:00 2001
From: contra
Date: Fri, 30 Dec 2016 13:15:50 -0500
Subject: [PATCH 031/216] make getting started more readable
---
docs/getting-started.md | 33 ++++++++++++++++-----------------
1 file changed, 16 insertions(+), 17 deletions(-)
diff --git a/docs/getting-started.md b/docs/getting-started.md
index cb3ecf553..e2e8dc83a 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -1,27 +1,24 @@
# Getting Started
-#### 1. Install gulp globally:
+*If you've previously installed a version of gulp globally, run `npm rm --global gulp` before following these instructions.*
-__If you have previously installed a version of gulp globally, please run `npm rm --global gulp`
-to make sure your old version doesn't collide with gulp-cli.__
+#### Install the `gulp` command
```sh
-$ npm install --global gulp-cli
+npm install --global gulp-cli
```
-#### 2. Initialize your project directory:
+#### Install `gulp` in your devDependencies
-```sh
-$ npm init
-```
-
-#### 3. Install gulp in your project devDependencies:
+Run this command in your project directory:
```sh
-$ npm install --save-dev gulp
+npm install --save-dev gulp
```
-#### 4. Create a `gulpfile.js` at the root of your project:
+#### Create a `gulpfile`
+
+Create a file called `gulpfile.js` in your project root with these contents:
```js
var gulp = require('gulp');
@@ -31,19 +28,21 @@ gulp.task('default', function() {
});
```
-#### 5. Run gulp:
+#### Test it out
+
+Run the gulp command in your project directory:
```sh
-$ gulp
+gulp
```
-The default task will run and do nothing.
+Voila! The default task will run and do nothing.
-To run individual tasks, use `gulp `.
+To run multiple tasks, you can use `gulp `.
## Where do I go now?
-You have an empty gulpfile and everything is installed. How do you REALLY get started? Check out the [recipes](recipes) and the [list of articles](README.md#articles) for more information.
+You have an empty gulpfile and everything is installed. Check out the [recipes](recipes) and the [list of articles](README.md#articles) for more information.
## .src, .watch, .dest, CLI args - How do I use these things?
From 0070cb162abf56f195ac8a0adca8047a249707d1 Mon Sep 17 00:00:00 2001
From: contra
Date: Fri, 30 Dec 2016 13:17:43 -0500
Subject: [PATCH 032/216] more readable getting started
---
docs/getting-started.md | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/docs/getting-started.md b/docs/getting-started.md
index e2e8dc83a..1b3bab799 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -1,6 +1,6 @@
# Getting Started
-*If you've previously installed a version of gulp globally, run `npm rm --global gulp` before following these instructions.*
+*If you've previously installed gulp globally, run `npm rm --global gulp` before following these instructions.*
#### Install the `gulp` command
@@ -42,12 +42,7 @@ To run multiple tasks, you can use `gulp `.
## Where do I go now?
-You have an empty gulpfile and everything is installed. Check out the [recipes](recipes) and the [list of articles](README.md#articles) for more information.
-
-## .src, .watch, .dest, CLI args - How do I use these things?
-
-For API specific documentation you can check out the [documentation for that](API.md).
-
-## Available Plugins
-
-The gulp community is growing, with new plugins being added daily. See the [main website](http://gulpjs.com/plugins/) for a complete list.
+- [API Documentation](API.md)
+- [Recipes](recipes)
+- [Help Articles](README.md#articles)
+- [Plugins](http://gulpjs.com/plugins/)
From 3f798f5d28782d3ed1da0f25dc9785bb36cc5680 Mon Sep 17 00:00:00 2001
From: contra
Date: Wed, 25 Jan 2017 12:20:02 -0500
Subject: [PATCH 033/216] add a little not about testing 4.0
---
README.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/README.md b/README.md
index 3789d085f..aff68a898 100644
--- a/README.md
+++ b/README.md
@@ -86,6 +86,16 @@ We recommend these plugins:
- [gulp-remember](https://github.com/ahaurw01/gulp-remember) - pairs nicely with gulp-cached
- [gulp-newer](https://github.com/tschaub/gulp-newer) - pass through newer source files only, supports many:1 source:dest
+## Want to test the latest and greatest?
+
+We're hard at work on our latest release, but we need your help! Install it, use it, and open issues if anything isn't right!
+
+```sh
+npm install gulpjs/gulp#4.0
+```
+
+There's a slew of major (wonderful) changes in 4.0, so make sure you check out the [docs on that branch](https://github.com/gulpjs/gulp/tree/4.0)!
+
## Want to contribute?
Anyone can help make this project better - check out our [Contributing guide](/CONTRIBUTING.md)!
From 325bb225874f86cd9bbb5dafdcdc79dcec9a4ff1 Mon Sep 17 00:00:00 2001
From: contra
Date: Wed, 25 Jan 2017 12:21:03 -0500
Subject: [PATCH 034/216] wow that was overexcited
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index aff68a898..8a5ddebab 100644
--- a/README.md
+++ b/README.md
@@ -88,7 +88,7 @@ We recommend these plugins:
## Want to test the latest and greatest?
-We're hard at work on our latest release, but we need your help! Install it, use it, and open issues if anything isn't right!
+We're hard at work on our latest release, but we need your help testing it!
```sh
npm install gulpjs/gulp#4.0
From 90340b9e64c1e88debc2238fda14b25a4270fb49 Mon Sep 17 00:00:00 2001
From: Mordax
Date: Tue, 31 Jan 2017 11:27:27 -0500
Subject: [PATCH 035/216] Replace tags with keywords in package.json (#1894)
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index b60ba7d52..edf2e2e89 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
"homepage": "http://gulpjs.com",
"repository": "gulpjs/gulp",
"author": "Fractal (http://wearefractal.com/)",
- "tags": [
+ "keywords": [
"build",
"stream",
"system",
From 62323fc55dd080a58ed030c5e9df176bdf551eae Mon Sep 17 00:00:00 2001
From: Kyle Cordes
Date: Thu, 23 Feb 2017 16:26:44 -0600
Subject: [PATCH 036/216] Docs: Clarify CLI semantics when listing more than
one task (#1916)
---
docs/CLI.md | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/docs/CLI.md b/docs/CLI.md
index 46c1ffb9d..a536c913f 100644
--- a/docs/CLI.md
+++ b/docs/CLI.md
@@ -22,7 +22,20 @@ Refer to this [StackOverflow](http://stackoverflow.com/questions/23023650/is-it-
### Tasks
-Tasks can be executed by running `gulp `. Just running `gulp` will execute the task you registered called `default`. If there is no `default` task gulp will error.
+Tasks can be executed by running `gulp ...`.
+
+If more than one task is listed, Gulp will execute all of them
+concurrently, that is, as if they had all been listed as dependencies of
+a single task.
+
+Gulp does not serialize tasks listed on the command line. From using
+other comparable tools users may expect to execute something like
+`gulp clean build`, with tasks named `clean` and `build`. This will not
+produce the intended result, as the two tasks will be executed
+concurrently.
+
+Just running `gulp` will execute the task `default`. If there is no
+`default` task, gulp will error.
### Compilers
From a2badd687dddd7a5c66599eeb0b4d25452c61ced Mon Sep 17 00:00:00 2001
From: Simon Meusel
Date: Mon, 1 May 2017 17:17:39 +0200
Subject: [PATCH 037/216] Docs: Fix issue with formatting in
dealing-with-streams.md (#1948)
---
docs/writing-a-plugin/dealing-with-streams.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/writing-a-plugin/dealing-with-streams.md b/docs/writing-a-plugin/dealing-with-streams.md
index 4c6d53830..57d390b96 100644
--- a/docs/writing-a-plugin/dealing-with-streams.md
+++ b/docs/writing-a-plugin/dealing-with-streams.md
@@ -8,7 +8,7 @@
## Dealing with streams
-Let's implement a plugin prepending some text to files. This plugin supports all possible forms of file.contents.
+Let's implement a plugin prepending some text to files. This plugin supports all possible forms of `file.contents`.
```js
var through = require('through2');
@@ -73,7 +73,7 @@ gulp.src('files/**/*.js', { buffer: false })
.pipe(gulp.dest('modified-files'));
```
-## Some plugins using streams
+## Some plugins using streams
* [gulp-svgicons2svgfont](https://github.com/nfroidure/gulp-svgiconstosvgfont)
From d634e9577bd8bb7ef59b74674a64f08495d0c971 Mon Sep 17 00:00:00 2001
From: Tamara Jordan
Date: Wed, 17 May 2017 18:29:57 +0100
Subject: [PATCH 038/216] Docs: Fix sub-lists in writing-a-plugin guidelines
(#1955)
---
docs/writing-a-plugin/guidelines.md | 52 ++++++++++++++---------------
1 file changed, 26 insertions(+), 26 deletions(-)
diff --git a/docs/writing-a-plugin/guidelines.md b/docs/writing-a-plugin/guidelines.md
index 4c924574c..8d97e4e9c 100644
--- a/docs/writing-a-plugin/guidelines.md
+++ b/docs/writing-a-plugin/guidelines.md
@@ -5,45 +5,45 @@
[Writing a Plugin](README.md) > Guidelines
1. Your plugin should not do something that can be done easily with an existing node module
- - For example: deleting a folder does not need to be a gulp plugin. Use a module like [del](https://github.com/sindresorhus/del) within a task instead.
- - Wrapping every possible thing just for the sake of wrapping it will pollute the ecosystem with low quality plugins that don't make sense within the gulp paradigm.
- - gulp plugins are for file-based operations! If you find yourself shoehorning a complex process into streams just make a normal node module instead.
- - A good example of a gulp plugin would be something like gulp-coffee. The coffee-script module does not work with Vinyl out of the box, so we wrap it to add this functionality and abstract away pain points to make it work well within gulp.
+ - For example: deleting a folder does not need to be a gulp plugin. Use a module like [del](https://github.com/sindresorhus/del) within a task instead.
+ - Wrapping every possible thing just for the sake of wrapping it will pollute the ecosystem with low quality plugins that don't make sense within the gulp paradigm.
+ - gulp plugins are for file-based operations! If you find yourself shoehorning a complex process into streams just make a normal node module instead.
+ - A good example of a gulp plugin would be something like gulp-coffee. The coffee-script module does not work with Vinyl out of the box, so we wrap it to add this functionality and abstract away pain points to make it work well within gulp.
1. Your plugin should only do **one thing**, and do it well.
- - Avoid config options that make your plugin do completely different tasks
- - For example: A JS minification plugin should not have an option that adds a header as well
+ - Avoid config options that make your plugin do completely different tasks
+ - For example: A JS minification plugin should not have an option that adds a header as well
1. Your plugin shouldn't do things that other plugins are responsible for
- - It should not concat, [gulp-concat](https://github.com/contra/gulp-concat) does that
- - It should not add headers, [gulp-header](https://www.npmjs.com/package/gulp-header) does that
- - It should not add footers, [gulp-footer](https://www.npmjs.com/package/gulp-footer) does that
- - If it's a common but optional use case, document that your plugin is often used with another plugin
- - Make use of other plugins within your plugin! This reduces the amount of code you have to write and ensures a stable ecosystem.
+ - It should not concat, [gulp-concat](https://github.com/contra/gulp-concat) does that
+ - It should not add headers, [gulp-header](https://www.npmjs.com/package/gulp-header) does that
+ - It should not add footers, [gulp-footer](https://www.npmjs.com/package/gulp-footer) does that
+ - If it's a common but optional use case, document that your plugin is often used with another plugin
+ - Make use of other plugins within your plugin! This reduces the amount of code you have to write and ensures a stable ecosystem.
1. Your plugin **must be tested**
- - Testing a gulp plugin is easy, you don't even need gulp to test it
- - Look at other plugins for examples
+ - Testing a gulp plugin is easy, you don't even need gulp to test it
+ - Look at other plugins for examples
1. Add `gulpplugin` as a keyword in your `package.json` so you show up on our search
1. Your plugin API should be a function that returns a stream
- - If you need to store state somewhere, do it internally
- - If you need to pass state/options between plugins, tack it on the file object
+ - If you need to store state somewhere, do it internally
+ - If you need to pass state/options between plugins, tack it on the file object
1. Do not throw errors inside a stream
- - Instead, you should emit it as an **error** event.
- - If you encounter an error **outside** the stream, such as invalid configuration while creating the stream, you may throw it.
+ - Instead, you should emit it as an **error** event.
+ - If you encounter an error **outside** the stream, such as invalid configuration while creating the stream, you may throw it.
1. Prefix any errors with the name of your plugin
- - For example: `gulp-replace: Cannot do regexp replace on a stream`
- - Use gulp-util's [PluginError](https://github.com/gulpjs/gulp-util#new-pluginerrorpluginname-message-options) class to make this easy
+ - For example: `gulp-replace: Cannot do regexp replace on a stream`
+ - Use gulp-util's [PluginError](https://github.com/gulpjs/gulp-util#new-pluginerrorpluginname-message-options) class to make this easy
1. Name your plugin appropriately: it should begin with "gulp-" if it is a gulp plugin
- - If it is not a gulp plugin, it should not begin with "gulp-"
+ - If it is not a gulp plugin, it should not begin with "gulp-"
1. The type of `file.contents` should always be the same going out as it was when it came in
- - If file.contents is null (non-read) just ignore the file and pass it along
- - If file.contents is a Stream and you don't support that just emit an error
- - Do not buffer a stream to shoehorn your plugin to work with streams. This will cause horrible things to happen.
+ - If file.contents is null (non-read) just ignore the file and pass it along
+ - If file.contents is a Stream and you don't support that just emit an error
+ - Do not buffer a stream to shoehorn your plugin to work with streams. This will cause horrible things to happen.
1. Do not pass the `file` object downstream until you are done with it
1. Use [`file.clone()`](https://github.com/gulpjs/vinyl#clone) when cloning a file or creating a new one based on a file.
1. Use modules from our [recommended modules page](recommended-modules.md) to make your life easier
1. Do NOT require `gulp` as a dependency or peerDependency in your plugin
- - Using gulp to test or automate your plugin workflow is totally cool, just make sure you put it as a devDependency
- - Requiring gulp as a dependency of your plugin means that anyone who installs your plugin is also installing a new gulp and its entire dependency tree.
- - There is no reason you should be using gulp within your actual plugin code. If you find yourself doing this open an issue so we can help you out.
+ - Using gulp to test or automate your plugin workflow is totally cool, just make sure you put it as a devDependency
+ - Requiring gulp as a dependency of your plugin means that anyone who installs your plugin is also installing a new gulp and its entire dependency tree.
+ - There is no reason you should be using gulp within your actual plugin code. If you find yourself doing this open an issue so we can help you out.
## Why are these guidelines so strict?
From a0ec3ff91c84baa1bd8de5331a502e330f5e3cfe Mon Sep 17 00:00:00 2001
From: Packt
Date: Wed, 24 May 2017 01:09:34 +0530
Subject: [PATCH 039/216] Docs: Add "Getting Started with Gulp" to books
section (#1961)
---
docs/README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/docs/README.md b/docs/README.md
index fbcef8bcd..9d63fe3f8 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -26,6 +26,7 @@ Post on [StackOverflow with a #gulp tag](http://stackoverflow.com/questions/tagg
## Books
* [Developing a gulp Edge](http://shop.oreilly.com/product/9781939902146.do)
+* [Getting Started with Gulp – Second Edition](https://www.packtpub.com/application-development/getting-started-gulp-%E2%80%93-second-edition) - Travis Maynard, Packt (April 2017)
## Articles
From 45adfc35aeeeaac5678ee63d20a6cdf985f6ceaf Mon Sep 17 00:00:00 2001
From: Terin Stock
Date: Sat, 17 Jun 2017 15:04:16 -0700
Subject: [PATCH 040/216] Docs: Integrate pump documentation from gulp-uglify
(closes #1791)
---
docs/README.md | 1 +
docs/why-use-pump/README.md | 122 +++++++++++++++++++++++++++++++
docs/why-use-pump/pipe-error.png | Bin 0 -> 144530 bytes
docs/why-use-pump/pump-error.png | Bin 0 -> 67191 bytes
4 files changed, 123 insertions(+)
create mode 100644 docs/why-use-pump/README.md
create mode 100644 docs/why-use-pump/pipe-error.png
create mode 100644 docs/why-use-pump/pump-error.png
diff --git a/docs/README.md b/docs/README.md
index 9d63fe3f8..253859992 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -4,6 +4,7 @@
* [API documentation](API.md) - Learn the ins and outs of using gulp
* [CLI documentation](CLI.md) - Learn how to call tasks and use compilers
* [Writing a Plugin](writing-a-plugin/README.md) - So you're writing a gulp plugin? Go here for the essential dos and don'ts.
+* [Why Use Pump?](why-use-pump/README.md) - Why you should use the `pump` module instead of calling `.pipe` yourself.
* [Spanish documentation][SpanishDocs] - gulp en Español.
* [Simplified Chinese documentation][SimplifiedChineseDocs] - gulp 简体中文文档.
* [Korean documentation][KoreanDocs] - gulp 한국어 참조 문서.
diff --git a/docs/why-use-pump/README.md b/docs/why-use-pump/README.md
new file mode 100644
index 000000000..de6ebc85f
--- /dev/null
+++ b/docs/why-use-pump/README.md
@@ -0,0 +1,122 @@
+# Why Use Pump?
+
+When using `pipe` from the Node.js streams, errors are not propagated forward
+through the piped streams, and source streams aren’t closed if a destination
+stream closed. The [`pump`][pump] module normalizes these problems and passes
+you the errors in a callback.
+
+## A common gulpfile example
+
+A common pattern in gulp files is to simply return a Node.js stream, and expect
+the gulp tool to handle errors.
+
+```javascript
+// example of a common gulpfile
+var gulp = require('gulp');
+var uglify = require('gulp-uglify');
+
+gulp.task('compress', function () {
+ // returns a Node.js stream, but no handling of error messages
+ return gulp.src('lib/*.js')
+ .pipe(uglify())
+ .pipe(gulp.dest('dist'));
+});
+```
+
+
+
+There’s an error in one of the JavaScript files, but that error message is the
+opposite of helpful. You want to know what file and line contains the error. So
+what is this mess?
+
+When there’s an error in a stream, the Node.js stream fire the 'error' event,
+but if there’s no handler for this event, it instead goes to the defined
+[uncaught exception][uncaughtException] handler. The default behavior of the
+uncaught exception handler is documented:
+
+> By default, Node.js handles such exceptions by printing the stack trace to
+> stderr and exiting.
+
+## Handling the Errors
+
+Since allowing the errors to make it to the uncaught exception handler isn’t
+useful, we should handle the exceptions properly. Let’s give that a quick shot.
+
+```javascript
+var gulp = require('gulp');
+var uglify = require('gulp-uglify');
+
+gulp.task('compress', function () {
+ return gulp.src('lib/*.js')
+ .pipe(uglify())
+ .pipe(gulp.dest('dist'))
+ .on('error', function(err) {
+ console.error('Error in compress task', err.toString());
+ });
+});
+```
+
+Unfortunately, Node.js stream’s `pipe` function doesn’t forward errors through
+the chain, so this error handler only handles the errors given by
+`gulp.dest`. Instead we need to handle errors for each stream.
+
+```javascript
+var gulp = require('gulp');
+var uglify = require('gulp-uglify');
+
+gulp.task('compress', function () {
+ function createErrorHandler(name) {
+ return function (err) {
+ console.error('Error from ' + name + ' in compress task', err.toString());
+ };
+ }
+
+ return gulp.src('lib/*.js')
+ .on('error', createErrorHandler('gulp.src'))
+ .pipe(uglify())
+ .on('error', createErrorHandler('uglify'))
+ .pipe(gulp.dest('dist'))
+ .on('error', createErrorHandler('gulp.dest'));
+});
+```
+
+This is a lot of complexity to add in each of your gulp tasks, and it’s easy to
+forget to do it. In addition, it’s still not perfect, as it doesn’t properly
+signal to gulp’s task system that the task has failed. We can fix this, and we
+can handle the other pesky issues with error propogations with streams, but it’s
+even more work!
+
+## Using pump
+
+The [`pump`][pump] module is a cheat code of sorts. It’s a wrapper around the
+`pipe` functionality that handles these cases for you, so you can stop hacking
+on your gulpfiles, and get back to hacking new features into your app.
+
+```javascript
+var gulp = require('gulp');
+var uglify = require('gulp-uglify');
+var pump = require('pump');
+
+gulp.task('compress', function (cb) {
+ pump([
+ gulp.src('lib/*.js'),
+ uglify(),
+ gulp.dest('dist')
+ ],
+ cb
+ );
+});
+```
+
+The gulp task system provides a gulp task with a callback, which can signal
+successful task completion (being called with no arguments), or a task failure
+(being called with an Error argument). Fortunately, this is the exact same
+format `pump` uses!
+
+
+
+Now it’s very clear what plugin the error was from, what the error actually was,
+and from what file and line number.
+
+[pump]: https://github.com/mafintosh/pump
+[uncaughtException]: https://nodejs.org/api/process.html#process_event_uncaughtexception
diff --git a/docs/why-use-pump/pipe-error.png b/docs/why-use-pump/pipe-error.png
new file mode 100644
index 0000000000000000000000000000000000000000..126856a4a6de7614d784941f812ba5c8cb6a9205
GIT binary patch
literal 144530
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