├── .gitignore ├── LICENSE ├── README.md ├── examples ├── advanced │ └── gulpfile.js ├── files │ ├── big.txt │ └── small.txt └── simple │ └── gulpfile.js ├── gulpfile.js ├── index.js ├── lib ├── compress.js └── utils.js ├── package.json └── test ├── files ├── big.txt ├── small.txt └── too_small.txt └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_STORE 3 | examples/**.txt 4 | !examples/files/*.txt 5 | examples/**.txt.gz 6 | !examples/files/*.txt.gz 7 | test/**.txt 8 | !test/files/*.txt 9 | test/**.txt.gz 10 | !test/files/*.txt.gz 11 | test/tmp 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Jeremy Stuckey 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | gulp-gzip 2 | ========= 3 | 4 | Gzip plugin for [gulp](https://github.com/wearefractal/gulp). 5 | 6 | # Install 7 | 8 | ``` 9 | npm install --save-dev gulp-gzip 10 | ``` 11 | 12 | # Options 13 | 14 | ### append `Boolean` 15 | 16 | Appends `.gz` file extension if true. Defaults to true. 17 | 18 | ```javascript 19 | gzip({ append: true }) 20 | ``` 21 | `filename.txt` becomes `filename.txt.gz`. 22 | 23 | ### extension `String` 24 | 25 | Appends an arbitrary extension to the filename. Disables `append` and `preExtension` options. 26 | 27 | ```javascript 28 | gzip({ extension: 'zip' }) // note that the `.` should not be included in the extension 29 | ``` 30 | `filename.txt` becomes `filename.txt.zip`. 31 | 32 | ### preExtension `String` 33 | 34 | Appends an arbitrary pre-extension to the filename. Disables `append` and `extension` options. 35 | 36 | ```javascript 37 | gzip({ preExtension: 'gz' }) // note that the `.` should not be included in the extension 38 | ``` 39 | `filename.txt` becomes `filename.gz.txt`. 40 | 41 | ### threshold `String|Number|Boolean` 42 | 43 | Minimum size required to compress a file. Defaults to false. 44 | 45 | ```javascript 46 | gzip({ threshold: '1kb' }) 47 | ``` 48 | 49 | ```javascript 50 | gzip({ threshold: 1024 }) 51 | ``` 52 | 53 | ```javascript 54 | gzip({ threshold: true }) 55 | ``` 56 | 57 | ### gzipOptions `Object` 58 | 59 | Options object to pass through to zlib.Gzip. See [zlib documentation][gzip-options] for more information. 60 | 61 | ```javascript 62 | gzip({ gzipOptions: { level: 9 } }) 63 | ``` 64 | 65 | ```javascript 66 | gzip({ gzipOptions: { memLevel: 1 } }) 67 | ``` 68 | 69 | ### deleteMode `String|Function` 70 | 71 | Some webserver modules such as nginx `gzip_static` looks for `example.html.gz`, serve it if it exists, else the original `example.html` will be served. 72 | 73 | For instance, if `example.html` was 2kb, it would be gzipped and `example.html.gz` was created. 74 | 75 | However, if later `example.html` is modified to content less than the threshold, gulp-gzip will only bypass it. Hence, you will end up with a new `example.html` yet old `example.html.gz`. Your webserver will continue to serve old content (`example.html.gz`). 76 | 77 | Using this option, gulp-gzip will remove `example.html.gz`. 78 | 79 | It takes in the same argument as `gulp.dest` as in `gulp.dest('mydest')`, so it knows where to look for the gzipped files. Defaults to `undefined`. 80 | 81 | ```javascript 82 | gzip({ threshold: 1024, deleteMode: 'mydest' }) 83 | ``` 84 | 85 | If you have `cwd` as in `gulp.dest('mydest', { cwd: mycwd })`. You can configure it using `deleteModeCwd`. 86 | 87 | ```javascript 88 | gzip({ threshold: 1024, deleteMode: 'mydest', deleteModeCwd: mycwd }) 89 | ``` 90 | 91 | ### skipGrowingFiles `Boolean` 92 | 93 | Some files actually get larger after compression. If true, this option passes along the original, uncompressed file if compression increases the file size. Defaults to false. 94 | 95 | ```javascript 96 | gzip({ skipGrowingFiles : true }) 97 | ``` 98 | 99 | # Examples 100 | 101 | ```javascript 102 | var gulp = require('gulp'); 103 | var gzip = require('gulp-gzip'); 104 | 105 | gulp.task('compress', function() { 106 | gulp.src('./dev/scripts/*.js') 107 | .pipe(gzip()) 108 | .pipe(gulp.dest('./public/scripts')); 109 | }); 110 | ``` 111 | 112 | ```javascript 113 | var gulp = require('gulp'); 114 | var coffee = require('gulp-coffee'); 115 | var concat = require('gulp-concat'); 116 | var uglify = require('gulp-uglify'); 117 | var gzip = require('gulp-gzip'); 118 | 119 | gulp.task('deployScripts', function() { 120 | gulp.src('./dev/scripts/*.coffee') 121 | .pipe(coffee()) 122 | .pipe(concat('all.js')) 123 | .pipe(uglify()) 124 | .pipe(gzip()) 125 | .pipe(gulp.dest('./public/scripts')); 126 | }); 127 | ``` 128 | 129 | ```javascript 130 | var gulp = require('gulp'); 131 | var tar = require('gulp-tar'); 132 | var gzip = require('gulp-gzip'); 133 | 134 | gulp.task('tarball', function() { 135 | gulp.src('./files/*') 136 | .pipe(tar('archive.tar')) 137 | .pipe(gzip()) 138 | .pipe(gulp.dest('.')); 139 | }); 140 | ``` 141 | 142 | [More examples](https://github.com/jstuckey/gulp-gzip/tree/master/examples). 143 | 144 | 145 | [gzip-options]: https://nodejs.org/api/zlib.html#zlib_class_options 146 | -------------------------------------------------------------------------------- /examples/advanced/gulpfile.js: -------------------------------------------------------------------------------- 1 | var del = require('del'); 2 | var gulp = require('gulp'); 3 | var gzip = require('../../index'); 4 | 5 | var config = { 6 | threshold: '1kb' 7 | }; 8 | 9 | gulp.task('clean', function(cb) { 10 | return del('tmp', cb); 11 | }); 12 | 13 | gulp.task('small', function() { 14 | return gulp.src('../files/small.txt') 15 | .pipe(gzip(config)) 16 | .pipe(gulp.dest('tmp')); 17 | }); 18 | 19 | gulp.task('big', function() { 20 | return gulp.src('../files/big.txt') 21 | .pipe(gzip(config)) 22 | .pipe(gulp.dest('tmp')); 23 | }); 24 | 25 | gulp.task('large', function() { 26 | return gulp.src('../files/large.txt', { buffer: false }) 27 | .pipe(gzip(config)) 28 | .pipe(gulp.dest('tmp')); 29 | }); 30 | 31 | gulp.task('default', gulp.series('clean', 'small', 'big', 'large')); 32 | -------------------------------------------------------------------------------- /examples/files/big.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatibus, eaque animi autem distinctio assumenda. Necessitatibus, dicta, aliquam architecto aut error quaerat at beatae harum modi earum sequi accusantium labore nisi rerum neque nemo et quae dolorem voluptas dolorum blanditiis accusamus repellat illo saepe quisquam alias doloribus non temporibus quasi maiores distinctio eos unde ad ipsam excepturi vel praesentium repudiandae minus amet consequatur suscipit laboriosam qui asperiores possimus exercitationem nesciunt ratione odio reprehenderit deserunt iure! Doloremque deserunt rem vitae iure ipsam esse tempore veritatis voluptate natus blanditiis. Velit, porro, fuga enim quasi voluptatum praesentium ea autem fugit unde non architecto quisquam reprehenderit cumque laboriosam dolore saepe eligendi similique iste quis expedita beatae itaque possimus repellendus officiis nam minima blanditiis numquam voluptatem optio temporibus asperiores adipisci quas necessitatibus cum natus hic provident? Autem, atque, voluptate, dicta, sequi adipisci doloribus aspernatur ipsa beatae rem odio doloremque odit consequuntur vitae cupiditate quos repellendus id eligendi excepturi pariatur molestiae praesentium quasi perspiciatis quaerat quisquam blanditiis architecto minus ad possimus porro illum quibusdam ipsam culpa voluptatibus iste ex earum quae quam laboriosam deleniti in expedita esse! Nihil, laboriosam, rem, consequatur ullam ipsam reiciendis tempora aliquam quos cupiditate saepe facere recusandae tenetur odio nulla officia molestiae atque harum ipsa nobis dolorum voluptatum suscipit consequuntur deleniti iusto delectus hic a numquam neque aliquid asperiores ipsum impedit nisi voluptas beatae facilis culpa eveniet unde animi architecto omnis fugiat magni? Placeat, autem, vero, aspernatur, ab impedit nisi delectus sequi hic aliquid officia cupiditate praesentium voluptates veniam doloremque cumque aliquam enim quas reprehenderit aut dolor possimus inventore saepe fuga in dignissimos ipsam ut et eum sed tempore error a labore beatae incidunt repellat animi perferendis rerum iure tempora odio nam earum nulla asperiores est laboriosam facilis? Perspiciatis, fugiat, veniam, voluptatem ad eligendi optio veritatis autem voluptas deleniti incidunt provident soluta mollitia nesciunt fugit recusandae. Porro, nostrum, ab, inventore velit quidem impedit voluptatum placeat tempora mollitia unde nisi itaque dolorum perspiciatis temporibus excepturi omnis nobis. Itaque, provident, laudantium aperiam unde ex laborum vero quam placeat porro accusantium quia non alias facilis illum corporis dolor voluptatum aspernatur expedita deserunt labore beatae illo nobis hic ea vel omnis velit iste magnam odit asperiores delectus autem praesentium minima recusandae ipsa nisi eligendi ipsam. Est, animi, ipsam natus culpa cumque excepturi molestiae sit tenetur rem aspernatur assumenda laborum sequi sed tempora praesentium rerum reiciendis qui quidem cum possimus. Dolorem, ad delectus temporibus quasi repudiandae dicta repellendus! 2 | -------------------------------------------------------------------------------- /examples/files/small.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quis, eaque, rerum maxime quod repellat ipsam modi sit voluptatibus quidem et. Mollitia dicta atque modi. Recusandae, doloribus dolores praesentium culpa quisquam quasi maiores aperiam itaque minima incidunt hic in similique quas. Unde, ut nam ipsum doloribus praesentium neque sapiente dolorum beatae totam rem! Tempora, dolorem, nesciunt, dolorum veritatis earum aliquam a quae rem saepe vitae quaerat ex aliquid voluptates eum nobis repellat natus neque voluptatem veniam exercitationem nam eaque iste sequi officia perspiciatis! Earum, hic alias aperiam repellat tenetur labore mollitia unde dolorum eligendi consequatur asperiores neque excepturi officia? Ducimus sed velit ipsa iure libero eos doloremque at eveniet facilis quibusdam! Optio, veniam adipisci eius error sequi. Pariatur, vitae vero quia et illum alias saepe aperiam enim! Deleniti ipsam repellat labore. 2 | -------------------------------------------------------------------------------- /examples/simple/gulpfile.js: -------------------------------------------------------------------------------- 1 | var del = require('del'); 2 | var gulp = require('gulp'); 3 | var gzip = require('../../index'); 4 | 5 | gulp.task('clean', function(cb) { 6 | return del('tmp', cb); 7 | }); 8 | 9 | gulp.task('compress', gulp.series('clean', function() { 10 | return gulp.src('../files/small.txt') 11 | .pipe(gzip()) 12 | .pipe(gulp.dest('tmp')); 13 | })); 14 | 15 | gulp.task('default', gulp.series('compress')); 16 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var del = require('del'); 2 | var filter = require('gulp-filter'); 3 | var gulp = require('gulp'); 4 | var mocha = require('gulp-mocha'); 5 | var watch = require('gulp-watch'); 6 | var jshint = require('gulp-jshint'); 7 | var stylish = require('jshint-stylish'); 8 | 9 | var root = __dirname; 10 | 11 | gulp.task('clean', function(cb) { 12 | return del([ 13 | 'examples/*/tmp', 14 | 'test/tmp' 15 | ], cb); 16 | }); 17 | 18 | gulp.task('lint', function() { 19 | return gulp.src([ 'index.js', 'test/test.js', 'lib/*.js' ]) 20 | .pipe(jshint({ expr: true })) 21 | .pipe(jshint.reporter(stylish)); 22 | }); 23 | 24 | gulp.task('test', function() { 25 | // monkeys are fixing `cwd` for `gulp-mocha` 26 | // node lives in one process/scope/directory 27 | process.chdir(root); 28 | 29 | return gulp.src('test/test.js') 30 | .pipe(mocha({ reporter: 'spec', timeout: 1000 })) 31 | }); 32 | 33 | gulp.task('watch', function() { 34 | watch({ 35 | glob: [ 'index.js', 'lib/*.js' , 'test/test.js' ], 36 | read: false 37 | }, ['clean', 'lint', 'test']) 38 | }); 39 | 40 | gulp.task('default', gulp.series('watch')); 41 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*jslint node: true */ 2 | 'use strict'; 3 | 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | var through2 = require('through2'); 7 | var PluginError = require('plugin-error'); 8 | var fancyLog = require('fancy-log'); 9 | var colors = require('ansi-colors'); 10 | var utils = require('./lib/utils'); 11 | var compress = require('./lib/compress.js'); 12 | 13 | var PLUGIN_NAME = 'gulp-gzip'; 14 | 15 | module.exports = function (options) { 16 | 17 | // Combine user defined options with default options 18 | var defaultConfig = { 19 | append: true, 20 | threshold: false, 21 | gzipOptions: {}, 22 | skipGrowingFiles: false 23 | }; 24 | var config = utils.merge(defaultConfig, options); 25 | 26 | // Create a through2 object stream. This is our plugin export 27 | var stream = through2.obj(gulpGzip); 28 | 29 | // Expose the config so we can test it 30 | stream.config = config; 31 | 32 | function gulpGzip(file, enc, done) { 33 | 34 | /*jshint validthis: true */ 35 | var self = this; 36 | 37 | // Check for empty file 38 | if (file.isNull()) { 39 | // Pass along the empty file to the next plugin 40 | self.push(file); 41 | done(); 42 | return; 43 | } 44 | 45 | // Call when finished with compression 46 | var finished = function(err, contents, wasCompressed) { 47 | if (err) { 48 | var error = new PluginError(PLUGIN_NAME, err, { showStack: true }); 49 | self.emit('error', error); 50 | done(); 51 | return; 52 | } 53 | 54 | var complete = function() { 55 | file.contents = contents; 56 | self.push(file); 57 | done(); 58 | }; 59 | 60 | var getFixedPath = function(filepath) { 61 | if (config.extension) { 62 | filepath += '.' + config.extension; 63 | } else if (config.preExtension) { 64 | filepath = filepath.replace(/(\.[^\.]+)$/, '.' + config.preExtension + '$1'); 65 | } else if (config.append) { 66 | filepath += '.gz'; 67 | } 68 | 69 | return filepath; 70 | }; 71 | 72 | if (wasCompressed) { 73 | if (file.contentEncoding) { 74 | file.contentEncoding.push('gzip'); 75 | } else { 76 | file.contentEncoding = [ 'gzip' ]; 77 | } 78 | 79 | file.path = getFixedPath(file.path); 80 | complete(); 81 | } else if (config.deleteMode) { 82 | var cwd = path.resolve(config.deleteModeCwd || process.cwd()); 83 | var directory = typeof config.deleteMode === 'string' ? config.deleteMode : config.deleteMode(file); 84 | var filepath = path.resolve(cwd, directory, getFixedPath(file.relative)); 85 | 86 | fs.exists(filepath, function(exists) { 87 | if(exists) { 88 | fancyLog(colors.green('Gzipped file ' + filepath + ' deleted')); 89 | fs.unlink(filepath, complete); 90 | } else { 91 | complete(); 92 | } 93 | }); 94 | } else { 95 | complete(); 96 | } 97 | 98 | return; 99 | }; 100 | 101 | compress(file.contents, config, finished); 102 | } 103 | 104 | return stream; 105 | }; 106 | -------------------------------------------------------------------------------- /lib/compress.js: -------------------------------------------------------------------------------- 1 | var zlib = require('zlib'); 2 | var Readable = require('stream').Readable; 3 | var toArray = require('stream-to-array'); 4 | 5 | function convertContentsToBuffer(contents, callback) { 6 | if (contents instanceof Buffer) { 7 | callback(null, contents); 8 | } else { 9 | toArray(contents, function (err, chunks) { 10 | if (err) { 11 | callback(err, null); 12 | return; 13 | } 14 | 15 | callback(null, Buffer.concat(chunks)); 16 | }); 17 | } 18 | } 19 | 20 | function convertContentsToStream(contents, callback) { 21 | if (contents instanceof Readable) { 22 | callback(null, contents); 23 | } else { 24 | var rs = new Readable({ objectMode: true }); 25 | rs._read = function() { 26 | rs.push(contents); 27 | rs.push(null); 28 | }; 29 | callback(null, rs); 30 | } 31 | } 32 | 33 | module.exports = function(originalContents, options, callback) { 34 | 35 | convertContentsToBuffer(originalContents, function(err, contentsAsBuffer) { 36 | if (err) { 37 | callback(err, null, false); 38 | return; 39 | } 40 | 41 | var originalContentLength = contentsAsBuffer.length; 42 | 43 | // Check if the threshold option is set 44 | // If true, check if the buffer length is greater than the threshold 45 | if (options.threshold && originalContentLength < options.threshold) { 46 | // File size is smaller than the threshold 47 | // Pass it along to the next plugin without compressing 48 | if (originalContents instanceof Buffer) { 49 | callback(null, contentsAsBuffer, false); 50 | } else { 51 | convertContentsToStream(contentsAsBuffer, function(err, contentsAsStream) { 52 | callback(null, contentsAsStream, false); 53 | }); 54 | } 55 | return; 56 | } 57 | 58 | convertContentsToStream(contentsAsBuffer, function(err, contentsAsStream) { 59 | if (err) { 60 | callback(err, null, false); 61 | return; 62 | } 63 | 64 | // Compress the contents 65 | var gzipStream = zlib.createGzip(options.gzipOptions); 66 | contentsAsStream.pipe(gzipStream); 67 | 68 | convertContentsToBuffer(gzipStream, function(err, compressedContentsAsBuffer) { 69 | if (err) { 70 | callback(err, null, false); 71 | return; 72 | } 73 | 74 | if (options.skipGrowingFiles && compressedContentsAsBuffer.length >= originalContentLength) { 75 | callback(null, originalContents, false); 76 | } else { 77 | if (originalContents instanceof Buffer) { 78 | callback(null, compressedContentsAsBuffer, true); 79 | } else { 80 | convertContentsToStream(compressedContentsAsBuffer, function(err, compressedContentsStream) { 81 | callback(null, compressedContentsStream, true); 82 | }); 83 | } 84 | } 85 | }); 86 | }); 87 | }); 88 | }; 89 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | var bytes = require('bytes'); 2 | 3 | // Merge source object with target object while handling threshold option 4 | // Used to merge user defined plugin options with default options 5 | function merge(target, source) { 6 | if (typeof source === 'undefined') source = {}; 7 | 8 | Object.keys(source).forEach(function(key) { 9 | if (key === 'threshold') { 10 | target[key] = threshold(source[key]); 11 | } else { 12 | target[key] = source[key]; 13 | } 14 | }); 15 | 16 | return target; 17 | } 18 | 19 | // Parse the threshold plugin option 20 | // Specifies the minimum file size that will be compressed 21 | // Can be a string, number, or boolean 22 | function threshold(obj) { 23 | var ret; 24 | 25 | switch (typeof obj) { 26 | case 'string': 27 | ret = bytes(obj) < 150 ? 150 : bytes(obj); 28 | break; 29 | case 'number': 30 | ret = obj < 150 ? 150 : obj; 31 | break; 32 | case 'boolean': 33 | ret = obj === false ? false : 150; 34 | break; 35 | default: 36 | throw new Error('threshold must be String|Number|Boolean'); 37 | } 38 | 39 | return ret; 40 | } 41 | 42 | exports.merge = merge; 43 | exports.threshold = threshold; 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-gzip", 3 | "version": "1.4.2", 4 | "license": "MIT", 5 | "description": "Gzip plugin for gulp.", 6 | "keywords": [ 7 | "compress", 8 | "gulpplugin", 9 | "gzip" 10 | ], 11 | "repository": "https://github.com/jstuckey/gulp-gzip.git", 12 | "homepage": "https://github.com/jstuckey/gulp-gzip/", 13 | "author": "Jeremy Stuckey ", 14 | "main": "index.js", 15 | "scripts": { 16 | "test": "gulp" 17 | }, 18 | "engines": { 19 | "node": ">= 0.10.0" 20 | }, 21 | "licenses": [ 22 | { 23 | "type": "MIT", 24 | "url": "http://github.com/jstuckey/gulp-gzip/raw/master/LICENSE" 25 | } 26 | ], 27 | "dependencies": { 28 | "ansi-colors": "^1.0.1", 29 | "bytes": "^3.0.0", 30 | "fancy-log": "^1.3.2", 31 | "plugin-error": "^1.0.0", 32 | "stream-to-array": "^2.3.0", 33 | "through2": "^2.0.3" 34 | }, 35 | "devDependencies": { 36 | "del": "^3.0.0", 37 | "gulp": "^4.0.0", 38 | "gulp-filter": "^5.1.0", 39 | "gulp-jshint": "^2.1.0", 40 | "gulp-mocha": "^6.0.0", 41 | "gulp-rename": "^1.2.0", 42 | "gulp-tap": "^0.1.1", 43 | "gulp-watch": "5.0.1", 44 | "jshint": "^2.9.5", 45 | "jshint-stylish": "~0.1.5", 46 | "mocha": "^5.2.0", 47 | "nid": "^0.3.2", 48 | "should": "^3.2.0-beta1" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/files/big.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatibus, eaque animi autem distinctio assumenda. Necessitatibus, dicta, aliquam architecto aut error quaerat at beatae harum modi earum sequi accusantium labore nisi rerum neque nemo et quae dolorem voluptas dolorum blanditiis accusamus repellat illo saepe quisquam alias doloribus non temporibus quasi maiores distinctio eos unde ad ipsam excepturi vel praesentium repudiandae minus amet consequatur suscipit laboriosam qui asperiores possimus exercitationem nesciunt ratione odio reprehenderit deserunt iure! Doloremque deserunt rem vitae iure ipsam esse tempore veritatis voluptate natus blanditiis. Velit, porro, fuga enim quasi voluptatum praesentium ea autem fugit unde non architecto quisquam reprehenderit cumque laboriosam dolore saepe eligendi similique iste quis expedita beatae itaque possimus repellendus officiis nam minima blanditiis numquam voluptatem optio temporibus asperiores adipisci quas necessitatibus cum natus hic provident? Autem, atque, voluptate, dicta, sequi adipisci doloribus aspernatur ipsa beatae rem odio doloremque odit consequuntur vitae cupiditate quos repellendus id eligendi excepturi pariatur molestiae praesentium quasi perspiciatis quaerat quisquam blanditiis architecto minus ad possimus porro illum quibusdam ipsam culpa voluptatibus iste ex earum quae quam laboriosam deleniti in expedita esse! Nihil, laboriosam, rem, consequatur ullam ipsam reiciendis tempora aliquam quos cupiditate saepe facere recusandae tenetur odio nulla officia molestiae atque harum ipsa nobis dolorum voluptatum suscipit consequuntur deleniti iusto delectus hic a numquam neque aliquid asperiores ipsum impedit nisi voluptas beatae facilis culpa eveniet unde animi architecto omnis fugiat magni? Placeat, autem, vero, aspernatur, ab impedit nisi delectus sequi hic aliquid officia cupiditate praesentium voluptates veniam doloremque cumque aliquam enim quas reprehenderit aut dolor possimus inventore saepe fuga in dignissimos ipsam ut et eum sed tempore error a labore beatae incidunt repellat animi perferendis rerum iure tempora odio nam earum nulla asperiores est laboriosam facilis? Perspiciatis, fugiat, veniam, voluptatem ad eligendi optio veritatis autem voluptas deleniti incidunt provident soluta mollitia nesciunt fugit recusandae. Porro, nostrum, ab, inventore velit quidem impedit voluptatum placeat tempora mollitia unde nisi itaque dolorum perspiciatis temporibus excepturi omnis nobis. Itaque, provident, laudantium aperiam unde ex laborum vero quam placeat porro accusantium quia non alias facilis illum corporis dolor voluptatum aspernatur expedita deserunt labore beatae illo nobis hic ea vel omnis velit iste magnam odit asperiores delectus autem praesentium minima recusandae ipsa nisi eligendi ipsam. Est, animi, ipsam natus culpa cumque excepturi molestiae sit tenetur rem aspernatur assumenda laborum sequi sed tempora praesentium rerum reiciendis qui quidem cum possimus. Dolorem, ad delectus temporibus quasi repudiandae dicta repellendus! 2 | -------------------------------------------------------------------------------- /test/files/small.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quis, eaque, rerum maxime quod repellat ipsam modi sit voluptatibus quidem et. Mollitia dicta atque modi. Recusandae, doloribus dolores praesentium culpa quisquam quasi maiores aperiam itaque minima incidunt hic in similique quas. Unde, ut nam ipsum doloribus praesentium neque sapiente dolorum beatae totam rem! Tempora, dolorem, nesciunt, dolorum veritatis earum aliquam a quae rem saepe vitae quaerat ex aliquid voluptates eum nobis repellat natus neque voluptatem veniam exercitationem nam eaque iste sequi officia perspiciatis! Earum, hic alias aperiam repellat tenetur labore mollitia unde dolorum eligendi consequatur asperiores neque excepturi officia? Ducimus sed velit ipsa iure libero eos doloremque at eveniet facilis quibusdam! Optio, veniam adipisci eius error sequi. Pariatur, vitae vero quia et illum alias saepe aperiam enim! Deleniti ipsam repellat labore. 2 | -------------------------------------------------------------------------------- /test/files/too_small.txt: -------------------------------------------------------------------------------- 1 | abc 2 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var gulp = require('gulp'); 3 | var log = require('fancy-log'); 4 | var gzip = require('../'); 5 | var nid = require('nid'); 6 | var rename = require('gulp-rename'); 7 | var should = require('should'); 8 | var Stream = require('stream'); 9 | var tap = require('gulp-tap'); 10 | var zlib = require('zlib'); 11 | 12 | // monkeys are fixing cwd for gulp-mocha 13 | // node lives in one process/scope/directory 14 | process.chdir('./test'); 15 | 16 | describe('gulp-gzip', function() { 17 | 18 | describe('config', function() { 19 | 20 | it('should have default config', function(done) { 21 | var instance = gzip(); 22 | instance.config.should.eql({ 23 | append: true, 24 | gzipOptions: {}, 25 | skipGrowingFiles: false, 26 | threshold: false 27 | }); 28 | done(); 29 | }); 30 | 31 | it('should merge options with defaults', function(done) { 32 | var instance = gzip({ append: false }); 33 | instance.config.should.eql({ 34 | append: false, 35 | gzipOptions: {}, 36 | skipGrowingFiles: false, 37 | threshold: false 38 | }); 39 | done(); 40 | }); 41 | }); 42 | 43 | describe('file extension', function() { 44 | 45 | it('should append .gz to the file extension, by default', function(done) { 46 | gulp.src('files/small.txt') 47 | .pipe(gzip()) 48 | .pipe(tap(function(file) { 49 | file.path.should.endWith('.gz'); 50 | done(); 51 | })); 52 | }); 53 | 54 | it('should not append .gz to the file extension receiving { append: false }', function(done) { 55 | gulp.src('files/small.txt') 56 | .pipe(gzip({ append: false })) 57 | .pipe(tap(function(file) { 58 | file.path.should.not.endWith('.gz'); 59 | done(); 60 | })); 61 | }); 62 | 63 | it('should accept an arbitrary extension with the `extension` option', function(done) { 64 | gulp.src('files/small.txt') 65 | .pipe(gzip({ extension: 'zip' })) 66 | .pipe(tap(function(file) { 67 | file.path.should.endWith('.zip'); 68 | done(); 69 | })); 70 | }); 71 | 72 | it('should accept an arbitrary pre-extension with the `preExtension` option', function(done) { 73 | gulp.src('files/small.txt') 74 | .pipe(gzip({ preExtension: 'gz' })) 75 | .pipe(tap(function(file) { 76 | file.path.should.endWith('.gz.txt'); 77 | done(); 78 | })); 79 | }); 80 | }); 81 | 82 | describe('file type', function() { 83 | 84 | it('should return file contents as a Buffer', function(done) { 85 | gulp.src('files/small.txt') 86 | .pipe(gzip()) 87 | .pipe(tap(function(file) { 88 | file.contents.should.be.instanceof(Buffer); 89 | done(); 90 | })); 91 | }); 92 | 93 | it('should return file contents as a Stream', function(done) { 94 | gulp.src('files/small.txt', { buffer: false }) 95 | .pipe(gzip()) 96 | .pipe(tap(function(file) { 97 | file.contents.should.be.instanceof(Stream); 98 | done(); 99 | })); 100 | }); 101 | }); 102 | 103 | describe('file properties', function() { 104 | it('should not lose any properties from the Vinyl file', function(done) { 105 | gulp.src('files/small.txt') 106 | .pipe(tap(function(file) { 107 | file.test = 'test'; 108 | })) 109 | .pipe(gzip()) 110 | .pipe(tap(function(file) { 111 | file.should.have.property('test', 'test'); 112 | done(); 113 | })); 114 | }); 115 | 116 | it('should set `contentEncoding`', function(done) { 117 | gulp.src('files/small.txt') 118 | .pipe(gzip()) 119 | .pipe(tap(function(file) { 120 | file.should.have.property('contentEncoding'); 121 | file.contentEncoding.should.containEql('gzip'); 122 | done(); 123 | })); 124 | }); 125 | }); 126 | 127 | describe('gzip options', function() { 128 | 129 | it('should set gzipOptions object', function(done) { 130 | var instance = gzip({ gzipOptions: { level: 9, memLevel: 1} }); 131 | instance.config.should.have.property('gzipOptions'); 132 | instance.config.gzipOptions.should.have.property('level', 9); 133 | instance.config.gzipOptions.should.have.property('memLevel', 1); 134 | done(); 135 | }); 136 | 137 | it('should handle compression level in buffer mode', function(done) { 138 | var id_lowest_compression = nid(); 139 | var id_highest_compression = nid(); 140 | 141 | var out_lowest_compression = gulp.dest('tmp'); 142 | var out_highest_compression = gulp.dest('tmp'); 143 | 144 | var size_lowest_compression = 0; 145 | var size_highest_compression = 0; 146 | 147 | out_lowest_compression.on('end', function() { 148 | fs.stat('./tmp/' + id_lowest_compression + '.txt.gz', function (err, stats) { 149 | size_lowest_compression = stats.size; 150 | 151 | if (size_highest_compression > 0) { 152 | size_highest_compression.should.be.lessThan(size_lowest_compression); 153 | done(); 154 | } 155 | }); 156 | }); 157 | 158 | out_highest_compression.on('end', function() { 159 | fs.stat('./tmp/' + id_highest_compression + '.txt.gz', function (err, stats) { 160 | size_highest_compression = stats.size; 161 | 162 | if (size_lowest_compression > 0) { 163 | size_highest_compression.should.be.lessThan(size_lowest_compression); 164 | done(); 165 | } 166 | }); 167 | }); 168 | 169 | gulp.src('files/big.txt') 170 | .pipe(rename({ basename: id_lowest_compression })) 171 | .pipe(gzip({ gzipOptions: { level: 1 } })) 172 | .pipe(out_lowest_compression); 173 | 174 | gulp.src('files/big.txt') 175 | .pipe(rename({ basename: id_highest_compression })) 176 | .pipe(gzip({ gzipOptions: { level: 9 } })) 177 | .pipe(out_highest_compression); 178 | }); 179 | 180 | it('should handle compression level in stream mode', function(done) { 181 | var id_lowest_compression = nid(); 182 | var id_highest_compression = nid(); 183 | 184 | var out_lowest_compression = gulp.dest('tmp'); 185 | var out_highest_compression = gulp.dest('tmp'); 186 | 187 | var size_lowest_compression = 0; 188 | var size_highest_compression = 0; 189 | 190 | out_lowest_compression.on('end', function() { 191 | fs.stat('./tmp/' + id_lowest_compression + '.txt.gz', function (err, stats) { 192 | size_lowest_compression = stats.size; 193 | 194 | if (size_highest_compression > 0) { 195 | size_highest_compression.should.be.lessThan(size_lowest_compression); 196 | done(); 197 | } 198 | }); 199 | }); 200 | 201 | out_highest_compression.on('end', function() { 202 | fs.stat('./tmp/' + id_highest_compression + '.txt.gz', function (err, stats) { 203 | size_highest_compression = stats.size; 204 | 205 | if (size_lowest_compression > 0) { 206 | size_highest_compression.should.be.lessThan(size_lowest_compression); 207 | done(); 208 | } 209 | }); 210 | }); 211 | 212 | gulp.src('files/big.txt', { buffer: false }) 213 | .pipe(rename({ basename: id_lowest_compression })) 214 | .pipe(gzip({ gzipOptions: { level: 1 } })) 215 | .pipe(out_lowest_compression); 216 | 217 | gulp.src('files/big.txt', { buffer: false }) 218 | .pipe(rename({ basename: id_highest_compression })) 219 | .pipe(gzip({ gzipOptions: { level: 9 } })) 220 | .pipe(out_highest_compression); 221 | }); 222 | }); 223 | 224 | describe('threshold option', function() { 225 | 226 | it('should set threshold to false while receiving false', function(done) { 227 | var instance = gzip({ threshold: false }); 228 | instance.config.threshold.should.be.false; 229 | done(); 230 | }); 231 | 232 | it('should set threshold to 150 while receiving true', function(done) { 233 | var instance = gzip({ threshold: true }); 234 | instance.config.threshold.should.eql(150); 235 | done(); 236 | }); 237 | 238 | it('should set threshold to Number while receiving Number', function(done) { 239 | var instance = gzip({ threshold: 1024 }); 240 | instance.config.should.have.property('threshold', 1024); 241 | done(); 242 | }); 243 | 244 | it('should set threshold to 150 while receiving Number < 150', function(done) { 245 | var instance = gzip({ threshold: 100 }); 246 | instance.config.should.have.property('threshold', 150); 247 | done(); 248 | }); 249 | 250 | it('should set threshold to Number while receiving String (bytes result)', function(done) { 251 | var instance = gzip({ threshold: '1kb' }); 252 | instance.config.should.have.property('threshold', 1024); 253 | done(); 254 | }); 255 | 256 | it('should set threshold to 150 while receiving String (bytes result < 150)', function(done) { 257 | var instance = gzip({ threshold: '1kb' }); 258 | instance.config.should.have.property('threshold', 1024); 259 | done(); 260 | }); 261 | 262 | it('should handle threshold of 1kb by passing through small.txt (<1kb)', function(done) { 263 | var id = nid(); 264 | var out = gulp.dest('tmp'); 265 | 266 | out.on('end', function() { 267 | fs.readFile('./tmp/' + id + '.txt', { encoding: 'utf-8' }, function(err, file) { 268 | fs.readFile('./files/small.txt', { encoding: 'utf-8' }, function(err, original) { 269 | file.should.equal(original); 270 | done(); 271 | }); 272 | }); 273 | }); 274 | 275 | gulp.src('files/small.txt') 276 | .pipe(rename({ basename: id })) 277 | .pipe(gzip({ threshold: '1kb' })) 278 | .pipe(out); 279 | }); 280 | 281 | it('should handle threshold of 1kb by compressing big.txt (>1kb)', function(done) { 282 | var id = nid(); 283 | var out = gulp.dest('tmp'); 284 | 285 | out.on('end', function() { 286 | fs.readFile('./tmp/' + id + '.txt.gz', function(err, file) { 287 | zlib.unzip(file, function(err, buffer) { 288 | file = buffer.toString('utf-8'); 289 | 290 | fs.readFile('./files/big.txt', { encoding: 'utf-8' }, function(err, original) { 291 | file.should.equal(original); 292 | done(); 293 | }); 294 | }); 295 | }); 296 | }); 297 | 298 | gulp.src('files/big.txt') 299 | .pipe(rename({ basename: id })) 300 | .pipe(gzip({ threshold: '1kb' })) 301 | .pipe(out); 302 | }); 303 | 304 | it('should handle threshold of 1kb by passing through small.txt (<1kb)', function(done) { 305 | var id = nid(); 306 | var out = gulp.dest('tmp'); 307 | 308 | out.on('end', function() { 309 | fs.readFile('./tmp/' + id + '.txt', { encoding: 'utf-8' }, function(err, file) { 310 | fs.readFile('./files/small.txt', { encoding: 'utf-8' }, function(err, original) { 311 | file.should.equal(original); 312 | done(); 313 | }); 314 | }); 315 | }); 316 | 317 | gulp.src('files/small.txt', { buffer: false }) 318 | .pipe(rename({ basename: id })) 319 | .pipe(gzip({ threshold: '1kb' })) 320 | .pipe(out); 321 | }); 322 | 323 | it('should handle threshold of 1kb by compressing big.txt (>1kb)', function(done) { 324 | var id = nid(); 325 | var out = gulp.dest('tmp'); 326 | 327 | out.on('end', function() { 328 | fs.readFile('./tmp/' + id + '.txt.gz', function(err, file) { 329 | zlib.unzip(file, function(err, buffer) { 330 | file = buffer.toString('utf-8'); 331 | 332 | fs.readFile('./files/big.txt', { encoding: 'utf-8' }, function(err, original) { 333 | file.should.equal(original); 334 | done(); 335 | }); 336 | }); 337 | }); 338 | }); 339 | 340 | gulp.src('files/big.txt', { buffer: false }) 341 | .pipe(rename({ basename: id })) 342 | .pipe(gzip({ threshold: '1kb' })) 343 | .pipe(out); 344 | }); 345 | }); 346 | 347 | describe('delete mode', function() { 348 | 349 | it('should not delete existing gzipped files when { deleteMode : false }', function(done) { 350 | var id = nid(); 351 | var out = gulp.dest('tmp'); 352 | 353 | out.on('end', function() { 354 | fs.readFile('./tmp/' + id + '.txt.gz', function(err, file) { 355 | should.not.exist(err); 356 | should.exist(file); 357 | file.should.not.be.empty; 358 | 359 | var out = gulp.dest('tmp'); 360 | out.on('end', function() { 361 | fs.readFile('./tmp/' + id + '.txt.gz', function(err, file) { 362 | should.not.exist(err); 363 | should.exist(file); 364 | file.should.not.be.empty; 365 | done(); 366 | }); 367 | }); 368 | 369 | gulp.src('files/small.txt') 370 | .pipe(rename({ basename: id })) 371 | .pipe(gzip({ threshold: 1024 })) 372 | .pipe(out); 373 | }); 374 | }); 375 | 376 | gulp.src('files/big.txt') 377 | .pipe(rename({ basename: id })) 378 | .pipe(gzip({ threshold: 1024 })) 379 | .pipe(out); 380 | }); 381 | 382 | it('should delete existing gzipped files if the files changed from big.txt (over threshold) to small.txt (under threshold) when { deleteMode : true }', function(done) { 383 | var id = nid(); 384 | var out = gulp.dest('tmp'); 385 | 386 | out.on('end', function() { 387 | fs.readFile('./tmp/' + id + '.txt.gz', function(err, file) { 388 | should.not.exist(err); 389 | should.exist(file); 390 | file.should.not.be.empty; 391 | 392 | var out = gulp.dest('tmp'); 393 | 394 | out.on('end', function() { 395 | fs.exists('./tmp/' + id + '.txt.gz', function(exists) { 396 | exists.should.be.false; 397 | done(); 398 | }); 399 | }); 400 | 401 | gulp.src('files/small.txt') 402 | .pipe(rename({ basename: id })) 403 | .pipe(gzip({ threshold: 1024, deleteMode: 'tmp' })) 404 | .pipe(out); 405 | }); 406 | }); 407 | 408 | gulp.src('files/big.txt') 409 | .pipe(rename({ basename: id })) 410 | .pipe(gzip({ threshold: 1024, deleteMode: 'tmp' })) 411 | .pipe(out); 412 | }); 413 | }); 414 | 415 | describe ('uncompress the compressed file', function() { 416 | 417 | it('should match original in buffer mode', function(done) { 418 | var id = nid(); 419 | var out = gulp.dest('tmp'); 420 | 421 | out.on('end', function() { 422 | fs.readFile('./tmp/' + id + '.txt.gz', function(err, file) { 423 | zlib.unzip(file, function(err, buffer) { 424 | file = buffer.toString('utf-8', 0, buffer.length); 425 | 426 | fs.readFile('./files/small.txt', { encoding: 'utf-8' }, function(err, original) { 427 | file.should.equal(original); 428 | done(); 429 | }); 430 | }); 431 | }); 432 | }); 433 | 434 | gulp.src('files/small.txt') 435 | .pipe(rename({ basename: id })) 436 | .pipe(gzip()) 437 | .pipe(out); 438 | }); 439 | 440 | it('should match original in stream mode', function(done) { 441 | var id = nid(); 442 | var out = gulp.dest('tmp'); 443 | 444 | out.on('end', function() { 445 | fs.readFile('./tmp/' + id + '.txt.gz', function(err, file) { 446 | zlib.unzip(file, function(err, buffer) { 447 | file = buffer.toString('utf-8', 0, buffer.length); 448 | 449 | fs.readFile('./files/small.txt', { encoding: 'utf-8' }, function(err, original) { 450 | file.should.equal(original); 451 | done(); 452 | }); 453 | }); 454 | }); 455 | }); 456 | 457 | gulp.src('files/small.txt', { buffer: false }) 458 | .pipe(rename({ basename: id })) 459 | .pipe(gzip()) 460 | .pipe(out); 461 | }); 462 | }); 463 | 464 | describe('skip files that get larger after compression', function() { 465 | it('handles buffers', function(done) { 466 | var originalBuffer; 467 | gulp.src('files/too_small.txt') 468 | .pipe(tap(function(file) { 469 | originalBuffer = file.contents; 470 | })) 471 | .pipe(gzip({ skipGrowingFiles: true })) 472 | .pipe(tap(function(file) { 473 | file.contents.should.equal(originalBuffer); 474 | done(); 475 | })); 476 | }); 477 | 478 | it('handles streams', function(done) { 479 | var originalStream; 480 | gulp.src('files/too_small.txt', { buffer: false }) 481 | .pipe(tap(function(file) { 482 | originalStream = file.contents; 483 | })) 484 | .pipe(gzip({ skipGrowingFiles: true })) 485 | .pipe(tap(function(file) { 486 | file.contents.should.equal(originalStream); 487 | done(); 488 | })); 489 | }); 490 | }); 491 | }); 492 | --------------------------------------------------------------------------------