Skip to content

new way to pass the configuration to the encodings #232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: v2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 42 additions & 88 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,102 +43,64 @@ as compressing will transform the body.

#### Options

`compression()` accepts these properties in the options object. In addition to
those listed below, [zlib](http://nodejs.org/api/zlib.html) options may be
passed in to the options object or
[brotli](https://nodejs.org/api/zlib.html#zlib_class_brotlioptions) options.
`compression()` accepts these properties in the options object.

##### chunkSize
##### encodings

Type: `Number`<br>
Default: `zlib.constants.Z_DEFAULT_CHUNK`, or `16384`.
Type: `Object`<br>

See [Node.js documentation](http://nodejs.org/api/zlib.html#zlib_memory_usage_tuning)
regarding the usage.
Handles the configurations for each encoding. Setting options.encodings[encoding] = false will disable that encoding.

##### filter

Type: `Function`

A function to decide if the response should be considered for compression.
This function is called as `filter(req, res)` and is expected to return
`true` to consider the response for compression, or `false` to not compress
the response.

The default filter function uses the [compressible](https://www.npmjs.com/package/compressible)
module to determine if `res.getHeader('Content-Type')` is compressible.

##### level

Type: `Number`<br>
Default: `zlib.constants.Z_DEFAULT_COMPRESSION`, or `-1`

The level of zlib compression to apply to responses. A higher level will result
in better compression, but will take longer to complete. A lower level will
result in less compression, but will be much faster.

This is an integer in the range of `0` (no compression) to `9` (maximum
compression). The special value `-1` can be used to mean the "default
compression level", which is a default compromise between speed and
compression (currently equivalent to level 6).

- `-1` Default compression level (also `zlib.constants.Z_DEFAULT_COMPRESSION`).
- `0` No compression (also `zlib.constants.Z_NO_COMPRESSION`).
- `1` Fastest compression (also `zlib.constants.Z_BEST_SPEED`).
- `2`
- `3`
- `4`
- `5`
- `6` (currently what `zlib.constants.Z_DEFAULT_COMPRESSION` points to).
- `7`
- `8`
- `9` Best compression (also `zlib.constants.Z_BEST_COMPRESSION`).

**Note** in the list above, `zlib` is from `zlib = require('zlib')`.
Example:

##### memLevel
```js
const compression = require('compression')
const express = require('express')

const app = express()

app.use(
compression({
encodings: {
br: {
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]: 6
}
},
gzip: {
level: zlib.constants.Z_BEST_SPEED
},
deflate: false // Disable Deflate compression
}
})
)
```

Type: `Number`<br>
Default: `zlib.constants.Z_DEFAULT_MEMLEVEL`, or `8`
###### Supported Encodings

This specifies how much memory should be allocated for the internal compression
state and is an integer in the range of `1` (minimum level) and `9` (maximum
level).
- **`br` (Brotli):**

See [Node.js documentation](http://nodejs.org/api/zlib.html#zlib_memory_usage_tuning)
regarding the usage.
This specifies the options for configuring Brotli. See [Node.js documentation](https://nodejs.org/api/zlib.html#class-brotlioptions) for a complete list of available options.

##### brotli
- **gzip:**

Type: `Object`
This specifies the options for configuring gzip. See [Node.js documentation](https://nodejs.org/api/zlib.html#class-options) for a complete list of available options.

This specifies the options for configuring Brotli. See [Node.js documentation](https://nodejs.org/api/zlib.html#class-brotlioptions) for a complete list of available options.
- **deflate:**

This specifies the options for configuring deflate. See [Node.js documentation](https://nodejs.org/api/zlib.html#class-options) for a complete list of available options.

##### strategy

Type: `Number`<br>
Default: `zlib.constants.Z_DEFAULT_STRATEGY`
##### filter

This is used to tune the compression algorithm. This value only affects the
compression ratio, not the correctness of the compressed output, even if it
is not set appropriately.
Type: `Function`

- `zlib.constants.Z_DEFAULT_STRATEGY` Use for normal data.
- `zlib.constants.Z_FILTERED` Use for data produced by a filter (or predictor).
Filtered data consists mostly of small values with a somewhat random
distribution. In this case, the compression algorithm is tuned to
compress them better. The effect is to force more Huffman coding and less
string matching; it is somewhat intermediate between `zlib.constants.Z_DEFAULT_STRATEGY`
and `zlib.constants.Z_HUFFMAN_ONLY`.
- `zlib.constants.Z_FIXED` Use to prevent the use of dynamic Huffman codes, allowing
for a simpler decoder for special applications.
- `zlib.constants.Z_HUFFMAN_ONLY` Use to force Huffman encoding only (no string match).
- `zlib.constants.Z_RLE` Use to limit match distances to one (run-length encoding).
This is designed to be almost as fast as `zlib.constants.Z_HUFFMAN_ONLY`, but give
better compression for PNG image data.
A function to decide if the response should be considered for compression.
This function is called as `filter(req, res)` and is expected to return
`true` to consider the response for compression, or `false` to not compress
the response.

**Note** in the list above, `zlib` is from `zlib = require('zlib')`.
The default filter function uses the [compressible](https://www.npmjs.com/package/compressible)
module to determine if `res.getHeader('Content-Type')` is compressible.

##### threshold

Expand All @@ -154,14 +116,6 @@ at the time the response headers are written, then it is assumed the response is
_over_ the threshold. To guarantee the response size can be determined, be sure
set a `Content-Length` response header.

##### windowBits

Type: `Number`<br>
Default: `zlib.constants.Z_DEFAULT_WINDOWBITS`, or `15`

See [Node.js documentation](http://nodejs.org/api/zlib.html#zlib_memory_usage_tuning)
regarding the usage.

##### enforceEncoding

Type: `String`<br>
Expand Down
30 changes: 16 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,9 @@ module.exports.filter = shouldCompress
* @private
*/
var cacheControlNoTransformRegExp = /(?:^|,)\s*?no-transform\s*?(?:,|$)/
var SUPPORTED_ENCODING = ['br', 'gzip', 'deflate', 'identity']
var ENCODING_OPTIONS = ['br', 'gzip', 'deflate']
var PREFERRED_ENCODING = ['br', 'gzip']

var encodingSupported = ['gzip', 'deflate', 'identity', 'br']

/**
* Compress response data with gzip / deflate.
*
Expand All @@ -50,12 +48,14 @@ var encodingSupported = ['gzip', 'deflate', 'identity', 'br']
*/

function compression (options) {
var opts = options || {}
var optsBrotli = {
...opts.brotli,
const opts = options || {}
const encodingOpts = opts?.encodings
const encodingSupported = ENCODING_OPTIONS.filter(enc => encodingOpts?.[enc] !== false)
const optsBrotli = {
...encodingOpts?.br,
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]: 4, // set the default level to a reasonable value with balanced speed/ratio
...opts.brotli?.params
...encodingOpts?.br?.params
}
}

Expand Down Expand Up @@ -187,10 +187,10 @@ function compression (options) {

// compression method
var negotiator = new Negotiator(req)
var method = negotiator.encoding(SUPPORTED_ENCODING, PREFERRED_ENCODING)
var method = negotiator.encoding(encodingSupported, PREFERRED_ENCODING)

// if no method is found, use the default encoding
if (!req.headers['accept-encoding'] && encodingSupported.indexOf(enforceEncoding) !== -1) {
if (!req.headers['accept-encoding'] && encodingSupported.includes(enforceEncoding)) {
method = enforceEncoding
}

Expand All @@ -202,11 +202,13 @@ function compression (options) {

// compression stream
debug('%s compression', method)
stream = method === 'gzip'
? zlib.createGzip(opts)
: method === 'br'
? zlib.createBrotliCompress(optsBrotli)
: zlib.createDeflate(opts)
if (method === 'gzip') {
stream = zlib.createGzip(encodingOpts?.gzip)
} else if (method === 'br') {
stream = zlib.createBrotliCompress(optsBrotli)
} else if (method === 'deflate') {
stream = zlib.createDeflate(encodingOpts?.deflate)
}

// add buffered listeners to stream
addListeners(stream, stream.on, listeners)
Expand Down
Loading