Categories
Express JavaScript

Compress Express.js Responses with the Compression Middleware

Spread the love

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 data
  • zlib.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 codes
  • zlib.Z_HUFFMAN_ONLY — force Huffman encoding only
  • zlib.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.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *