TABLE OF CONTENTS

Learn How To Compress Your Responses With Express and Node.js

Author Sagi Liba
Sagi Liba on Aug 8, 2020
4 min šŸ•

Compression reduces up to 70% of the size of text-based files ( HTML, JS, CSS, etc..) and some compression algorithms can reduce the size even more, this will result in a much faster loading time for your clients and less bytes going over the wire.

Gzip compression is probably the most common algorithm in use today and is supported by all major browsers.

Integrate compression with Express

We can easily compress our serverā€™s responses with a simple Node.js compression middleware, Lets start with a simple server as our playground:

Copy
const express = require("express");
const port = process.env.PORT || 3000;
// Init express
const app = express();
// Server routes
app.get("/compress", (req, res) => {
res.send("Hello World!");
});
// Start server
app.listen(port, () => {
console.log(`Listening on port: ${port}`);
});

Install the middleware:

Copy
npm install compression

After itā€™s installed lets import it inside our server:

Copy
const compression = require("compression");

Now lets bind our compression middleware to the application:

Copy
...
...
// Init express
const app = express();
app.use(compression())
...
...

Here we did not supply any options to the compression middleware, this means any response the server returns will be automatically compressed.

Control the level of compression

To control the compression level we need the pass a number between 0 ā€“ 9 to the level property.

0 ā€“ no compression at all.

ā€¦

9 ā€“ the best compression available.

The higher the level of compression you use the more time it will take to compress your response.

We can set the default compression by not passing any parameters to the level property or by passing the value -1, this value will currently equal the value of 6 and it means it is the best compromise between compression and speed.

Example of setting a compression level:

Copy
app.use(compression({ level: 9 }));

Controlling the compression middleware

We can decide which responses we would like to compress or not by supplying a filtering function to the middleware:

Copy
const shouldCompress = (req, res) => {
if (req.headers["x-no-compression"]) {
// don't compress responses with this request header
return false;
}
// fallback to standard filter function
return compression.filter(req, res);
};
// Usage:
app.use(compression({ filter: shouldCompress }));

When you send a request with the header ā€œx-no-compressionā€ the compression middleware will not compress your response, for example using the fetch API:

Copy
// npm install node-fetch...
const fetch = require("node-fetch");
fetch("http://localhost:3000/compress", {
method: "GET",
headers: {
"x-no-compression": "Any true value",
},
}).catch((e) => console.log(e));

Iā€™m sending the request using Node.js, Node.js does not support fetch out of the box so Iā€™ve installed node-fetch.

As you can see Iā€™m sending a simple GET request to our server and Iā€™ve supplied the ā€œx-no-compressionā€ header, by doing so our filtering function will decide whether to compress the response or not.

You can pass any value you want inside ā€œx-no-compressionā€ header, just make sure its not a falsy value.

Before and After

Now that its all set up lets test our compression middleware by seeing how the response size changes.

The easiest way I could think of to increase the response size was to create a variable that will hold a really long text, by doing so the response size will increase.

Copy
app.get("/compress", (req, res) => {
// I've shortend the actual text size
const text = `Lorem Ipsum is simply dummy text of the ...`;
res.send(text.repeat(10));
});

The function repeat will return a new concatenated string which contains a specified number of copies of the string which we called it on.

While repeat is used to increase the size of the response it will make the response time much higher until the processing is done. For a more accurate response you can store a large text in a database and retrieve it, or for the purpose of testing the compression hard code the text like I did in the example, just remove the repeat function and add a large text.

THE RESULTS

Before compression the response size is 23.3KB

Before GZIP Compression

After compression the response size is 1.6KB

After GZIP Compression

I think the response size difference is truly impressive, the usual compression rate for the gzip algorithm is around 70%. We have here around 93% compression size difference but its mostly because we used the repeat function and the text is not diverse enough.

While I have not looked up the implementation of the gzip algorithm, the most basic compression algorithms usually finds repeating patterns in a given text and replaces them with a representing value instead, by doing so you can compress the text with values that later decompresses to the pattern found.

I hope you enjoyed this article and that it brought you VALUE.

Documentation about the compression plugin:

http://expressjs.com/en/resources/middleware/compression.html

Ā© 2020-present Sagi Liba. All Rights Reserved