Skip to content

Instantly share code, notes, and snippets.

@rc1
Last active December 17, 2015 12:49
Show Gist options
  • Select an option

  • Save rc1/5612964 to your computer and use it in GitHub Desktop.

Select an option

Save rc1/5612964 to your computer and use it in GitHub Desktop.
Jade Compiler Middleware for Connect.js. Behaves similar to [less-middleware](https://npmjs.org/package/less-middleware) but also looks for index.jade files. Has basic caching but should not be used for production code.
var jade = require('jade');
var path = require('path');
var fs = require('fs');
// Debug logger
var useDebugLog = (typeof process.env.DEBUG_JADE_MIDDLEWARE !== "undefined");
var debugLog = function () {
if (!useDebugLog) { return; }
console.log.apply(this, Array.prototype.slice.call(arguments, 0));
};
// # Middleware
module.exports = function (options) {
var pages = {};
var src = options.src;
// used for jade extends
var jadeOptions = options.jadeOptions;
return function (req, res, next) {
hasHTMLExtension(req.url, function (yN, extension) {
// if not finish
if (!yN) {
next();
return;
}
hasMatchingJadeFileInPages(src, req.url, pages, jadeOptions, function (yN, page) {
if (yN) {
page.shouldRenderToFile(function (yN) {
if (yN) {
page.renderToFile(next);
} else {
next();
}
});
} else {
next();
}
});
});
};
};
// ## Utils
// see if request may be for an HTML file
function hasHTMLExtension(url, callback) {
var extension = path.extname(url);
if (extension === "" || extension === ".html" /* || extension === ".htm" */) {
return callback(true, extension);
} else {
return callback(false);
}
}
// creates a jade page if it doesn't exist in cache
function hasMatchingJadeFileInPages(srcDir, url, pages, jadeOptions, callback) {
if (typeof pages[url] === 'undefined') {
// get the possible jade file path
var extension = path.extname(url);
var jadeFilePath;
var htmlFilePath;
if (extension === ".html" /* || extension === ".htm" */) {
jadeFilePath = path.join(srcDir, url.substring(0, url.length - extension.length) + ".jade");
htmlFilePath = path.join(srcDir, url);
} else {
jadeFilePath = path.join(srcDir, url + "/index.jade");
htmlFilePath = path.join(srcDir, url + "/index.html");
}
// see if the jadefile exsists
fs.exists(jadeFilePath, function (exsits) {
// store the result in a new HTML page
pages[url] = new HTMLPage({
matchingJadeFilePath: (exsits)?jadeFilePath:null,
htmlFilePath: htmlFilePath,
jadeOptions: jadeOptions
});
callback(!!pages[url].matchingJadeFilePath, pages[url]);
});
} else {
callback(!!pages[url].matchingJadeFilePath, pages[url]);
}
}
// ## HTML Page Object
var HTMLPage = function (options) {
this.matchingJadeFilePath = options.matchingJadeFilePath;
this.htmlFilePath = options.htmlFilePath;
this.lastRenderToFile = undefined;
this.jadeOptions = (typeof options.jadeOptions === 'undefined') ? { pretty: true } : options.jadeOptions;
};
HTMLPage.prototype.shouldRenderToFile = function (callback) {
if (!!this.matchingJadeFilePath && !this.lastRenderToFile) {
callback(true);
} else if (!!this.matchingJadeFilePath) {
var self = this;
fs.stat(this.matchingJadeFilePath, function (err, stats) {
if (err) {
console.error("jade-middleware::Could not stat .jade file");
console.error(err);
callback(false);
return;
}
callback(self.lastRenderToFile < stats.mtime);
});
} else {
callback(false);
}
};
HTMLPage.prototype.renderToFile = function (callback) {
this.lastRenderToFile = Date.now();
debugLog("jade-middleware::renderToFile", this.lastRenderToFile );
var self = this;
fs.readFile(this.matchingJadeFilePath, function (err, data) {
data = data.toString();
if (err) {
console.error("jade-middleware::Could not read .jade file");
console.error(err);
callback();
return;
}
var compileError = false;
var jadeCompiledFn;
var jadeString;
try {
jadeCompiledFn = jade.compile(data, self.jadeOptions);
} catch (e) {
compileError = e.toString();
}
jadeString = (compileError) ? compileError : jadeCompiledFn();
fs.writeFile(self.htmlFilePath, jadeString, function (err) {
if (err) {
console.error("jade-middleware::Could not read .jade file");
console.error(err);
}
callback();
});
});
};

Jade-Middleware

Jade Compiler Middleware for Connect.js.
Behaves similar to less-middleware but also looks for index.jade files. Has basic caching but should not be used for production code.

Example express.js static serving app with less and jade middleware compilers

/**
 * Module dependencies.
 */

var express = require('express');
var http = require('http');
var lessMiddleware = require('less-middleware');
var path = require('path');
var jadeMiddleware = require(path.join(__dirname, 'jade-middleware.js'));

var app = express();

app.configure(function(){
    app.set('port', process.env.PORT || 3000);
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(jadeMiddleware({
        src: path.join(__dirname, 'public'),
        jadeOptions: {
            pretty: true,
            filename: path.join(__dirname, 'public/main.jade')
        }
    }));
    app.use(lessMiddleware({
        src: path.join(__dirname, 'public')
    }));
    app.use(express.static(path.join(__dirname, 'public')));
    app.use(express.directory(path.join(__dirname, 'public')));
});

app.configure('production', function(){
    console.log("Should not be used for production");
});

http.createServer(app).listen(app.get('port'), function(){
    console.log("Express server listening on port " + app.get('port'));
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment