Skip to content

Instantly share code, notes, and snippets.

@marcusgadbem
Last active November 25, 2021 22:20
Show Gist options
  • Save marcusgadbem/ddde8a7ad302134e2c18 to your computer and use it in GitHub Desktop.
Save marcusgadbem/ddde8a7ad302134e2c18 to your computer and use it in GitHub Desktop.
Middleware to minify HTML output for express template render engines in which supports callbacks
/* app/controllers/index.js */
module.exports.index = function(req, res) {
res.render('index.html');
};
/* config/middlewares/render-minified.js */
/**
* Dependencies
*/
var Minifier = require('html-minifier');
/**
* Render with minified HTML (express + nunjucks)
* Works as a response.method that minifies html string
* after nunjucks.render compiles and callback
* @param {String} view
* @param {Object} options
*/
module.exports = exports = function(req, res, next) {
res.oldRender = res.render;
res.render = function(view, options) {
this.oldRender(view, options, function(err, html) {
if (err) throw err;
html = Minifier.minify(html, {
removeComments: true,
removeCommentsFromCDATA: true,
collapseWhitespace: true,
collapseBooleanAttributes: true,
removeAttributeQuotes: true,
removeEmptyAttributes: true
});
res.send(html);
});
};
next();
};
/* server.js */
var express = require('express'),
nunjucks = require('nunjucks'),
renderMinified = require('./app/config/middlewares/render-minified');
var app = express();
app.engine('html', nunjucks.render);
nunjucks.configure(env.views, {
autoescape: true,
express: app
});
// new response render which passes html-minifier as callback to express render engine
app.use(renderMinified);
/* global describe, it, before */
/* tests/middlewares/render-minified.js */
/* by @rafaelverger */
var assert = require('assert'),
sinon = require('sinon'),
renderMinified = require('../../app/config/middlewares/render-minified');
describe('render-minified.js', function(){
var renderSpy,
renderNextSpy,
resMock;
before(function() {
renderSpy = sinon.spy();
renderNextSpy = sinon.spy();
resMock = {render: renderSpy};
renderMinified({}, resMock, renderNextSpy);
});
it ('ensure response.render was overwritten by renderMinified module', function() {
assert(renderSpy !== resMock.render);
assert(renderSpy === resMock.oldRender);
assert(renderNextSpy.calledOnce);
assert(renderNextSpy.calledWithExactly());
});
it('ensure the new render function calls old one', function() {
var a = "index.html",
b = {foo: 'bar'};
resMock.render(a, b);
assert(renderSpy.calledOnce);
assert(renderSpy.calledWith(a, b));
});
});
@rafaelverger
Copy link

Alteração no override do render do render-minified:

/* render-minified.js */
module.exports = exports = function(req, res, next) {
    res.oldRender = res.render;
    res.render = function(view, options) {
        this.oldRender(view, options, function(err, html) {
            if (err) throw err;
            html = Minifier.minify(html, {
                removeComments: true,
                removeCommentsFromCDATA: true,
                collapseWhitespace: true,
                collapseBooleanAttributes: true,
                removeAttributeQuotes: true,
                removeEmptyAttributes: true
            });
            res.send(html);
        });
    };
    next();
};

E o teste:

/* global describe, it, before */

var assert = require('assert'),
    sinon = require('sinon'),
    renderMinified = require('../../app/config/middlewares/render-minified');

describe('render-minified.js', function(){

    var renderSpy,
        renderNextSpy,
        resMock;

    before(function() {
        renderSpy = sinon.spy();
        renderNextSpy = sinon.spy();
        resMock = {render: renderSpy}; // dont need to be a mock obj; must be a simple obj that will receive the new attribute oldRender
        renderMinified({}, resMock, renderNextSpy);
    });

    it ('ensure response.render was overwritten by renderMinified module', function() {
        assert(renderSpy !== resMock.render);
        assert(renderSpy === resMock.oldRender);
        assert(renderNextSpy.calledOnce);
        assert(renderNextSpy.calledWithExactly());
    });

    it('ensure the new render function calls old one', function() {
        var a = "index.html",
            b = {foo: 'bar'}; // options/locals

        resMock.render(a, b);
        assert(renderSpy.calledOnce);
        assert(renderSpy.calledWith(a, b));
    });
});

@marcusgadbem
Copy link
Author

MAGO NUNES.

@rafaelverger
Copy link

@marcusgadbem confere as alteracoes!

@marcusgadbem
Copy link
Author

@rafaelverger boa! passou. 👍
Atualizei e coloquei como publico. :)

@nachbarshund
Copy link

Thanks for that great middleware.

@ediblecode
Copy link

For line 12 of render-minified.js I has to use if (err) return next(err); otherwise my error handling didn't work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment