Skip to content

Instantly share code, notes, and snippets.

@miguelludert
Created October 23, 2012 15:31
Show Gist options
  • Save miguelludert/3939484 to your computer and use it in GitHub Desktop.
Save miguelludert/3939484 to your computer and use it in GitHub Desktop.
Less middleware for express
var
fs = require("fs"),
__ = require("underscore"),
url = require('url'),
less = require('less'),
path = require('path'),
regex = /\.less$/,
cache = {},
defaultOptions = {
src : "",
force : false,
compress : true
},
options = {},
send = function(pathname,res){
res.set('Content-Type', 'text/css');
res.send(cache[pathname].output);
},
log = function(key, val, type) {
if(options.debug || type === 'error') {
switch(type) {
case 'log':
case 'info':
case 'error':
case 'warn':
break;
default:
type = 'log';
}
console[type](' \033[90m%s :\033[0m \033[36m%s\033[0m', key, val);
}
},
lessError = function(err,res,next) {
// create a user friendly error
var message = [];
message.push(err.message);
message.push("Line :" + err.line.toString());
message.push("Index :" + err.index.toString());
message.push("-------------------------------------------------------");
__.each(err.extract,function(value){
message.push(value);
});
res.set('Content-Type', 'text/plain');
res.send(message.join('\n'));
// log to the console
log("LESS " + err.type + ' error', err.message, 'error');
log("LESS File", err.filename + ' ' + err.line + ':' + err.column, 'error');
return next(err);
},
error = function(err,next){
return next('ENOENT' == err.code ? null : err);
};
module.exports = function(custom_options){
__.extend(options,defaultOptions,custom_options);
return function(req,res,next){
if ('GET' != req.method.toUpperCase() && 'HEAD' != req.method.toUpperCase()) { return next(); }
var pathname = options.src + url.parse(req.url).pathname;
// if the file does not end in .less, leave the method.
if(!regex.test(pathname)){
return next();
}
// read file stats
fs.lstat(pathname,function(err,stats){
if (err) {
return error(err,next);
}
// if it's already been cached, send it and leave;
if( !options.force && cache[pathname] && cache[pathname].mtime.getTime() == stats.mtime.getTime()){
return send(pathname,res);
}
// if it's not been cached, read the file
fs.readFile(pathname,'utf8',function(err,str){
if (err) {
return error(err,next);
}
var parser = new less.Parser({
paths: [path.dirname(pathname)],
filename: pathname,
optimization: 0
});
// parse the contents
parser.parse(str, function(err, tree) {
if (err) {
return lessError(err,res,next);
}
var css = tree.toCSS({
compress: options.compress,
yuicompress: false
});
// cache the output
cache[pathname] = {
path : pathname,
output : css,
mtime : stats.mtime
};
// send the output
return send(pathname,res);
});
});
});
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment