Compressing our responses is a great way to speed up our Express app’s performance.
To do this, we can use the compression
middleware.
In this article, we’ll look at the options available to us for compressing data and how to send a compressed response with it.
Adding the Middleware
We can install the package by running:
npm install compression
Then we can include it with:
const compression = require('compression');
Options
The compression
middleware takes an options
parameter, which is an object that can have the following properties:
chunkSize
The chunk size of the compressed output. Default is 16384 bytes or zlib.Z_DEFAULT_CHUNK
, where zlib
is the zlib
Node package.
filter
A function that decides what kind of responses should be compressed. The function is called as filter(req, res)
and should return true
if the kind of response should be compressed and false
if it shouldn’t.
The default function uses the compressible
module to check if the res.getHeader('Content-Type')
is compressible.
level
The compression level to apply The higher the level of compression, the longer it’ll take to complete.
The values range from 0 (no compression) to 9 (highest level of compression). -1 can be used to mean the default compression level, which is equivalent to level 6.
memLevel
This sets how much memory should be allocated for compression and is an integer ranging from 1 for the minimum level to 9 for the maximum.
Default is zlib.Z_DEFAULT_MEMLEVEL
or 8.
strategy
This sets the compression algorithm. The value only differs in the compression ratio and doesn’t affect the content of the compressed output.
The following are available:
zlib.Z_DEFAULT_STRATEGY
— used for normal datazlib.Z_FILTERED
— used for data produced by a filter. Filtered data consists mostly of small values with a random distribution. This algorithm is tuned to compressed these kinds of data better. This algorithm forces more Huffman coding.zlib.Z_FIXED
— use to prevent the use of dynamic Huffman codeszlib.Z_HUFFMAN_ONLY
— force Huffman encoding onlyzlib.Z_RULE
— limit match distances to one, This gives a compression ratio as good as Huffman only, but gives better compression for PNG data
threshold
The byte threshold for response body size before compression is considered for the response. The default 1kb
. The value can be the number of bytes or any string applied by the bytes
module.
windowBits
The default value is zlib.Z_DEFAULT_WINDOWBITS
or 15.
.filter
The default filter function, which we can use to construct a custom filter function that extends the default action.
res.flush
A res.flush
method is added to force partially compressed response to be flushed to the client.
Example
For example, we can use it as follows:
const express = require('express');
const bodyParser = require('body-parser');
const compression = require('compression');
const app = express();
const shouldCompress = (req, res) => {
if (req.headers['x-no-compression']) {
return false
}
return compression.filter(req, res);
}
app.use(bodyParser.json());
app.use(compression({
filter: shouldCompress,
level: 7,
}));
app.get('/', (req, res) => {
const foo = 'foo';
res.send(foo.repeat(3000));
});
app.listen(3000);
In the code above, we add the compression
middleware and specify some options.
We specified that we compress our responses when the x-no-compression
header isn’t present.
Also, we changed the compression level.
With the x-no-compression
header present, our response is 9KB. After compression is enabled by removing the x-no-compression
header, the response is only 402 bytes.
As we can see, the difference is huge. This is because the text is repeated so it can just keep one part of it and then repeat it instead of storing the whole string.
Server-Sent Events
We can compress responses with server-sent events. To do this, we compress the content after a window of the output has been buffered.
Once we have that, then we can send the data to the client.
We can use the res.flush()
method to send whatever is present to the client.
For example, we can write:
const express = require('express');
const bodyParser = require('body-parser');
const compression = require('compression');
const app = express();
const shouldCompress = (req, res) => {
if (req.headers['x-no-compression']) {
return false
}
return compression.filter(req, res);
}
app.use(bodyParser.json());
app.use(compression({
filter: shouldCompress,
level: 7,
}));
app.get('/', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
const timer = setInterval(() => {
res.write('foo');
res.flush()
}, 2000) res.on('close', () => {
clearInterval(timer)
})
});
app.listen(3000);
To send a text event stream to the client, then we should see foo
on the screen added every 2 seconds.
Conclusion
The compression
middleware is useful for compressing regular responses and server-sent event output.
We can set options like compression level, chunk size, etc.
Also, if we want to compress server-side events, we should call res.flush
to send what’s what already buffered to the client compressed.