diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f70c2c2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ + +Copyright JS Foundation and other contributors + +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: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +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. diff --git a/README.md b/README.md index 1dd5890..1cb8946 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,33 @@ -# compression plugin for webpack +[![npm][npm]][npm-url] +[![deps][deps]][deps-url] +[![chat][chat]][chat-url] -## Usage +
+ + + + +

Compression Plugin

+

Compression plugin for Webpack.

+

+ +

Install

+ +```bash +npm i -D compression-webpack-plugin +``` + +

Usage

``` javascript var CompressionPlugin = require("compression-webpack-plugin"); module.exports = { plugins: [ new CompressionPlugin({ - asset: "{file}.gz", + asset: "[path].gz[query]", algorithm: "gzip", - regExp: /\.js$|\.html$/, + test: /\.js$|\.html$/, threshold: 10240, minRatio: 0.8 }) @@ -19,12 +37,59 @@ module.exports = { Arguments: -* `asset`: The target asset name. `{file}` is replaced with the original asset. Defaults to `"{file}.gz"`. -* `algorithm`: Can be a `function(buf, callback)` or a string. For a string the algorithm is tacken from `zlib`. Defaults to `"gzip"`. -* `regExp`: All assets matching this RegExp are processed. Defaults to every asset. +* `asset`: The target asset name. `[file]` is replaced with the original asset. `[path]` is replaced with the path of the original asset and `[query]` with the query. Defaults to `"[path].gz[query]"`. +* `algorithm`: Can be a `function(buf, callback)` or a string. For a string the algorithm is taken from `zlib` (or zopfli for `zopfli`). Defaults to `"gzip"`. +* `test`: All assets matching this RegExp are processed. Defaults to every asset. * `threshold`: Only assets bigger than this size are processed. In bytes. Defaults to `0`. * `minRatio`: Only assets that compress better that this ratio are processed. Defaults to `0.8`. -## License +Option Arguments for Zopfli (see [node-zopfli](https://github.com/pierreinglebert/node-zopfli#options) doc for details): +* verbose: Default: false, +* verbose_more: Default: false, +* numiterations: Default: 15, +* blocksplitting: Default: true, +* blocksplittinglast: Default: false, +* blocksplittingmax: Default: 15 + +

Maintainers

+ + + + + + + + + + +
+ +
+ Juho Vepsäläinen +
+ +
+ Joshua Wiens +
+ +
+ Kees Kluskens +
+ +
+ Sean Larkin +
+ + +[npm]: https://img.shields.io/npm/v/webpack-loader-seed.svg +[npm-url]: https://npmjs.com/package/webpack-loader-seed + +[deps]: https://david-dm.org/webpack-contrib/webpack-loader-seed.svg +[deps-url]: https://david-dm.org/webpack-contrib/webpack-loader-seed -MIT (http://www.opensource.org/licenses/mit-license.php) \ No newline at end of file +[chat]: https://img.shields.io/badge/gitter-webpack%2Fwebpack-brightgreen.svg +[chat-url]: https://gitter.im/webpack/webpack diff --git a/index.js b/index.js index 599b686..e3c519e 100644 --- a/index.js +++ b/index.js @@ -3,57 +3,85 @@ Author Tobias Koppers @sokra */ var async = require("async"); +var url = require('url'); -var Source = require("webpack/lib/Source"); - -function RawSource(value) { - Source.call(this); - this._value = value; -} -module.exports = RawSource; - -RawSource.prototype = Object.create(Source.prototype); -RawSource.prototype._bake = function() { - return { - source: this._value - }; -}; +var RawSource = require("webpack-sources/lib/RawSource"); function CompressionPlugin(options) { options = options || {}; - this.asset = options.asset || "{file}.gz"; + this.asset = options.asset || "[path].gz[query]"; this.algorithm = options.algorithm || "gzip"; + this.compressionOptions = {}; if(typeof this.algorithm === "string") { - var zlib = require("zlib"); - this.algorithm = zlib[this.algorithm]; - if(!this.algorithm) throw new Error("Algorithm not found in zlib"); - this.algorithm = this.algorithm.bind(zlib); + if (this.algorithm === "zopfli") { + try { + var zopfli = require("node-zopfli"); + } catch(err) { + throw new Error("node-zopfli not found"); + } + this.compressionOptions = { + verbose: options.hasOwnProperty('verbose') ? options.verbose : false, + verbose_more: options.hasOwnProperty('verbose_more') ? options.verbose_more : false, + numiterations: options.numiterations ? options.numiterations : 15, + blocksplitting: options.hasOwnProperty('blocksplitting') ? options.blocksplitting : true, + blocksplittinglast: options.hasOwnProperty('blocksplittinglast') ? options.blocksplittinglast : false, + blocksplittingmax: options.blocksplittingmax ? options.blocksplittingmax : 15 + }; + this.algorithm = function (content, options, fn) { + zopfli.gzip(content, options, fn); + }; + } else { + var zlib = require("zlib"); + this.algorithm = zlib[this.algorithm]; + if(!this.algorithm) throw new Error("Algorithm not found in zlib"); + this.compressionOptions = { + level: options.level || 9, + flush: options.flush, + chunkSize: options.chunkSize, + windowBits: options.windowBits, + memLevel: options.memLevel, + strategy: options.strategy, + dictionary: options.dictionary + }; + } } - this.regExp = options.regExp; + this.test = options.test || options.regExp; this.threshold = options.threshold || 0; this.minRatio = options.minRatio || 0.8; } module.exports = CompressionPlugin; CompressionPlugin.prototype.apply = function(compiler) { - compiler.plugin("compilation", function(compilation) { - compilation.plugin("optimize-assets", function(assets, callback) { - async.forEach(Object.keys(assets), function(file, callback) { - if(this.regExp && !this.regExp.test(file)) return callback(); - var asset = assets[file]; - var content = asset.source(); - if(!Buffer.isBuffer(content)) - content = new Buffer(content, "utf-8"); - var originalSize = content.length; - if(originalSize < this.threshold) return callback(); - this.algorithm(content, function(err, result) { - if(err) return callback(err); - if(result.length / originalSize > this.minRatio) return callback(); - var newFile = this.asset.replace(/\{file\}/g, file); - assets[newFile] = new RawSource(result); - callback(); - }.bind(this)); - }.bind(this), callback); - }.bind(this)); + compiler.plugin("emit", function(compilation, callback) { + var assets = compilation.assets; + async.forEach(Object.keys(assets), function(file, callback) { + if(Array.isArray(this.test)) { + if(this.test.every(function(t) { + return !t.test(file); + })) return callback(); + } else if(this.test && !this.test.test(file)) + return callback(); + var asset = assets[file]; + var content = asset.source(); + if(!Buffer.isBuffer(content)) + content = new Buffer(content, "utf-8"); + var originalSize = content.length; + if(originalSize < this.threshold) return callback(); + this.algorithm(content, this.compressionOptions, function(err, result) { + if(err) return callback(err); + if(result.length / originalSize > this.minRatio) return callback(); + var parse = url.parse(file); + var sub = { + file: file, + path: parse.pathname, + query: parse.query || "" + }; + var newFile = this.asset.replace(/\[(file|path|query)\]/g, function(p0,p1) { + return sub[p1]; + }); + assets[newFile] = new RawSource(result); + callback(); + }.bind(this)); + }.bind(this), callback); }.bind(this)); -}; \ No newline at end of file +}; diff --git a/package.json b/package.json index 4df6c64..ed5e908 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,24 @@ { - "name": "compression-webpack-plugin", - "version": "0.1.0", - "author": "Tobias Koppers @sokra", - "description": "Prepare compressed versions of assets to serve them with Content-Encoding", - "peerDependencies": { - "webpack": ">=0.11 <0.12" - }, - "dependencies": { - "async": "0.2.x" - }, - "homepage": "http://github.com/webpack/compression-webpack-plugin", - "repository": { - "type": "git", - "url": "http://github.com/webpack/compression-webpack-plugin.git" - }, - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/mit-license.php" - } - ] -} \ No newline at end of file + "name": "compression-webpack-plugin", + "version": "0.3.2", + "author": "Tobias Koppers @sokra", + "description": "Prepare compressed versions of assets to serve them with Content-Encoding", + "dependencies": { + "async": "0.2.x", + "webpack-sources": "^0.1.0" + }, + "optionalDependencies": { + "node-zopfli": "^2.0.0" + }, + "homepage": "http://github.com/webpack/compression-webpack-plugin", + "repository": { + "type": "git", + "url": "http://github.com/webpack/compression-webpack-plugin.git" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://www.opensource.org/licenses/mit-license.php" + } + ] +}