Skip to content

Instantly share code, notes, and snippets.

@myndzi
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save myndzi/8837944 to your computer and use it in GitHub Desktop.
Save myndzi/8837944 to your computer and use it in GitHub Desktop.
'use strict';
module.exports = function (app, opts) {
var fs = require('fs'),
path = require('path'),
join = path.join,
Promise = require('bluebird'),
extend = require('jquery-extend'),
dust = opts.helpers ?
require('dustjs-helpers') :
require('dustjs-linkedin')
;
opts = opts || { };
opts.extension = app.get('view engine') || 'dust';
opts.publicdir = opts.publicdir || 'public';
opts.viewPath = app.get('views') || '.';
opts.partialCache = opts.partialCache || { };
// in my app, another component keeps these up to date; the { } here is just so the code doesn't die without it
opts.mtimes = opts.mtimes || { };
// these are only used by the helpers, you can delete them
fs.readFileP = Promise.promisify(fs.readFile.bind(fs));
dust.compileP = Promise.promisify(dust.compile.bind(dust));
dust.renderP = Promise.promisify(dust.render.bind(dust));
var mtimes = opts.mtimes;
// helpers for cache busting -- these are just examples, can be used in
// a template like {@css url="foo/bar"/}
dust.helpers.css = function (chunk, ctx, bodies, params) {
var url = dust.helpers.tap(params.url, chunk, ctx),
path = join(opts.publicdir, url);
if (mtimes[path]) { url = url.replace(/css$/, mtimes[path]+'.css'); }
else { console.error('warning:', path, 'mtime=', mtimes[path]); }
chunk.write('<link rel="stylesheet" href="'+url+'">');
return chunk;
};
dust.helpers.js = function (chunk, ctx, bodies, params) {
var url = dust.helpers.tap(params.url, chunk, ctx),
path = join(opts.publicdir, url);
if (mtimes[path]) { url = url.replace(/js$/, mtimes[path]+'.js'); }
chunk.write('<script src="'+bust(params.url)+'"></script>');
return chunk;
};
// don't ask me why i put this in a closure, I just wanted a hard separation
(function (dust, opts) {
var fs = require('fs'), extname = require('path').extname;
var ext = opts.extension,
views = opts.viewPath,
partialCache = opts.partialCache;
// setting these functions so that I don't have to re-compile functions every request;
// i can just switch between the two
dust._onLoadCached = function(path, callback) {
if ('' == extname(path)) path += '.' + ext;
if ('/' !== path[0]) path = views + '/' + path;
if (partialCache[path]) {
callback(null, partialCache[path]);
} else {
read(path, callback);
}
};
dust._onLoadNoCache = function(path, callback) {
if ('' == extname(path)) path += '.' + ext;
if ('/' !== path[0]) path = views + '/' + path;
read(path, callback);
};
function read(path, callback) {
fs.readFile(path, function (err, data) {
data = data.toString();
if (err) { callback(err); }
else {
partialCache[path] = data;
callback(null, data);
}
});
}
})(dust, opts);
var render = function render(path, _opts, callback) {
_opts = _opts || { };
_opts.cache = _opts.cache || opts.cache;
/* context variables get merged into the second parameter
* along with 'settings', 'cache', and '_locals'
* this seems weird, but i don't know how else i'm
* supposed to get ONLY the context variables!
*/
var ctx = dust.makeBase(_opts);
delete ctx.settings;
delete ctx.cache;
delete ctx._locals;
var p, tmplName = path.slice(opts.publicdir.length+1);
// set the function that fixes the partial paths based on whether it
// should return results from the cache or not
dust.onLoad = (_opts.cache ? dust._onLoadCached : dust._onLoadNoCache);
if (_opts.cache && dust.cache[path]) {
p = dust.renderP(tmplName, ctx);
} else {
p = fs.readFileP(path).then(function (data) {
var compiled = dust.compile(data.toString(), tmplName);
dust.loadSource(compiled);
return dust.renderP(tmplName, ctx);
});
}
return p.then(callback.bind(null, null), callback.bind(null));
}
return render;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment