how to create a simple node server that compresses static files using gzip
Asked Answered
T

4

5

I've been on this for hours..

the first thing i did was follow this tutorial which had this code:

var express = require('express');
var app = express();

// New call to compress content
app.use(express.compress());    
app.use(express.static(__dirname + '/public'));
app.listen(3333);

naturally the code was outdated.. and I got this error:

Error: Most middleware (like compress) is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.

so i updated the code to:

var express = require('express');
var app = express();
var compression = require('compression')

app.use(compression());
app.use(express.static(__dirname + '/_public' ));    

app.listen(3333);

which worked fine.. but I saw no evidence of compression (how do i know? by viewing the chrome dev tools response headers:

enter image description here

it doesn't have the gzip content-encoding header like the one in the tutorial:

enter image description here

So tried using the zlib library instead:

var express = require('express');
var app     = express();
var maxAge  = 31557600000;
var zlib = require('zlib');
app.use(express.static(__dirname + '/_public' ));

app.get('/*', function(req,res)
{
  res.sendFile(__dirname + '/_public/index.html').pipe(zlib.createGunzip()).pipe(output);
});

app.listen(3333);

but that didn't work out either.. and i'm pretty much left bald at this point.. any help?

p.s. the compression docs say you can provide zlib options, but fail to provide any examples/explanation.


update: the question has been fully answered and marked as such (i hate moving target questions).. but I can't help but asking: and so how can you verify how much of your original payload got trimmed as a result of gzip compression? Since naturally the compressing/decompressing happens behinds the scenes and as such chrome dev tools will report the original size of the file in its networking tab:

enter image description here

Troopship answered 16/8, 2014 at 13:25 Comment(1)
What is the exact file size of your index.html?Hygienist
C
3

I believe your setup, using the compression module, is correct. I just don't think it compresses the files during development.

Try setting the NODE_ENV to "production", e.g.

$ NODE_ENV="production" $ node server.js

EDIT To your follow up question.

Essentially what you are seeing in Chrome Dev Tools is the result of the compressed gzip compression. This answer describes it better then I can:

"Size" is the number of bytes on the wire, and "content" is the actual size of the resource

gzip compression reduces the "on the wire" size of the resource.

So, in your example, there will be 450 KB for the end user to download.

Coffelt answered 16/8, 2014 at 17:7 Comment(3)
interesting.. so npm start is the same as running node %nodefile%.js.. b/c the script above is in a server.js file.. i'll just run $NODE_ENV='produciton';node server.jsTroopship
it worked! but simply running node server.js where server.js has all the code above doesn't work.. i had to actually update my package.json and put ` "scripts": { "start": "node server.js"}` in it then it worked! i'll award you the correct answer since you answered my question above.. but i'll also add a little follow up question if you don't mindTroopship
Sure, what's the follow up? I'll modify the answer to use node server.jsCoffelt
F
5

zlib.createGunzip() is for decompressing.

I think that using headers and streams works.

app.get('/', function(req,res){
  res.writeHead(200, {
  'Content-Encoding': 'gzip' });
 fs.createReadStream('_public/index.html').pipe(zlib.createGzip()).pipe(res);
});
Fated answered 16/8, 2014 at 14:55 Comment(0)
C
3

I believe your setup, using the compression module, is correct. I just don't think it compresses the files during development.

Try setting the NODE_ENV to "production", e.g.

$ NODE_ENV="production" $ node server.js

EDIT To your follow up question.

Essentially what you are seeing in Chrome Dev Tools is the result of the compressed gzip compression. This answer describes it better then I can:

"Size" is the number of bytes on the wire, and "content" is the actual size of the resource

gzip compression reduces the "on the wire" size of the resource.

So, in your example, there will be 450 KB for the end user to download.

Coffelt answered 16/8, 2014 at 17:7 Comment(3)
interesting.. so npm start is the same as running node %nodefile%.js.. b/c the script above is in a server.js file.. i'll just run $NODE_ENV='produciton';node server.jsTroopship
it worked! but simply running node server.js where server.js has all the code above doesn't work.. i had to actually update my package.json and put ` "scripts": { "start": "node server.js"}` in it then it worked! i'll award you the correct answer since you answered my question above.. but i'll also add a little follow up question if you don't mindTroopship
Sure, what's the follow up? I'll modify the answer to use node server.jsCoffelt
M
2

Also, specify threshold value for small files compression (under 1kb) :

app.use(compression({ threshold: 0 }));
Mountainside answered 20/6, 2016 at 10:14 Comment(0)
T
0

I faced the same issue as well, used the compression module, like so :

const app = express();
app.use(compression({threshold : 0}));
app.use(express.static(path));

I tested it by devtools looking for Content-Encoding: gzip on the response header but without success.

Apparently chrome cached the files after the first request, so when refreshing again I couldn't see the Content-Encoding: gzip cause it retrieved the file from the cache.

Therefore I hard refreshed the page (Chrome ignores the cache and will load all resources from the web page again.) by doing Ctrl+Shift+R or from UI by right clicking refresh icon and selecting hard refresh. Then I managed to see the Content-Encoding: gzip response header.

Tsarina answered 23/9, 2020 at 13:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.