Question

I'm using Express to build a web application. I want to merge, minify and serve .js files. I wrote a middleware, this is my code:

var fs = require('fs'),
    path = require('path'),
    uglify = require('uglify-js'),
    cache = '',
    scriptsDir = path.join(__dirname, '../scripts'),
    files = fs.readdirSync(scriptsDir);

// Sync read is not a problem since the following code is executed on startup
files.forEach(function(fname) {
    if (/^.*\.js$/.test(fname)) {
        cache += fs.readFileSync(path.join(scriptsDir, fname), 'utf8').toString();
    }
});
cache = uglify.minify(cache, { fromString: true }).code;

module.exports = function(req, res, next) {
    if (req.url === '/js/all.js')
        res.end(cache);
    else
        next();
};

The middleware is used this way:

app.use(compress());
[...]
app.use(app.router);
app.use(jsMerger); // Here is my middleware
app.use(express.static(path.join(__dirname, '../public')));

The problem is the response is not gzipped. Also, there are "no headers" in the response (I mean, no cache headers, no etags; other resources served with the static middleware have those headers). This is the response:

X-Powered-By: Express
Transfer-Encoding: chunked
Date: Wed, 12 Mar 2014 14:04:19 GMT
Connection: keep-alive

Am I missing something? How to compress the response?

Was it helpful?

Solution

After adding the line res.set('Content-Type', 'text/javascript') Express is gzipping the response. The code is

module.exports = function(req, res, next) {
    if (req.url === '/js/all.js') {
        res.set('Content-Type', 'text/javascript');
        res.end(cache);
    } else {
        next();
    }
};

Now the headers of the response are:

X-Powered-By: Express
Vary: Accept-Encoding
Transfer-Encoding: chunked
Date: Wed, 12 Mar 2014 14:45:45 GMT
Content-Type: text/javascript
Content-Encoding: gzip
Connection: keep-alive

The reason for this is how the compress middleware is designed. You can supply a filter option to compress:

app.use(express.compress({
    filter : function(req, res) {
        return /json|text|javascript/.test(res.getHeader('Content-Type'));
    }
});

the compression is applied only to the requests that match the filter. The default filter of is:

function(req, res){
    return /json|text|javascript|dart|image\/svg\+xml|application\/x-font-ttf|application\/vnd\.ms-opentype|application\/vnd\.ms-fontobject/.test(res.getHeader('Content-Type'));
};

If you do not supply a Content-Type header, the request will not pass the filter and express will not gzip the response.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top