Skip to content

Instantly share code, notes, and snippets.

@lennerd
Last active August 29, 2015 14:17
Show Gist options
  • Save lennerd/78fe961391c20c1ba6ed to your computer and use it in GitHub Desktop.
Save lennerd/78fe961391c20c1ba6ed to your computer and use it in GitHub Desktop.
Browserify Transformer for Nunjucks Templates
var through = require('through'),
path = require('path'),
nunjucks = require('nunjucks'),
appRootPath = require('app-root-path').path,
_ = require('underscore');
var getTemplateReg = /env\.getTemplate\(("(.*?)")/g;
/**
* Calculates the templates path relative to the app root path.
*/
function templatePath(templatePath) {
return path.relative(appRootPath, templatePath);
}
/**
* Browserify transformer for nunjucks templates
*/
function nunjucksify(file, options) {
var data, extension;
options = options || {};
extension = options.extension || ['.nunj'];
if (!Array.isArray(extension))
extension = [extension];
// Check for nunjucks template extension for skipping other content types
if (!_.contains(extension, path.extname(file)))
return through();
// The options hash gets directly passed to the nunjucks.precompileString function.
// The name option must be fixed to be unique in the precompiling process.
options = _.extend({
asFunction: true
}, options, {
name: templatePath(file)
});
data = '';
function write(buf) {
data += buf;
}
function buildModule(compiledTemplate) {
var module = [], requiredTemplates, requires;
if (options.asFunction) {
requiredTemplates = {};
// options.asFunction is true, so we need the nunjucks module for rendering inside the built module
module.push('var nunjucks = require(\'nunjucks\');');
compiledTemplate = compiledTemplate.replace(getTemplateReg, function(fullMatch, strMatch, pathMatch) {
var resolvedTemplatePath = templatePath(path.resolve(path.dirname(file), pathMatch));
// Store the template paths in the requiredPaths data set for later use.
requiredTemplates[resolvedTemplatePath] = pathMatch;
// Replace the getTemplate function call parameter (template file path) with our unique template path.
return fullMatch.replace(pathMatch, resolvedTemplatePath);
});
// Build the require statements for the needed templates to be known to browserify.
requires = _.values(requiredTemplates).map(function(path) {
return 'require(\'' + path + '\');';
});
// Do we have any required templates? Add them as simple statements to the generated module.
if (requires.length > 0)
module.push.apply(module, requires);
module.push(compiledTemplate);
} else {
compiledTemplate = compiledTemplate.replace(getTemplateReg, function(fullMatch, strMatch) {
return fullMatch.replace(strMatch, 'require(' + strMatch + ')');
});
// options.asFunction is false, so we need to return the absolute template name to be able to use it inside
// other modules
module.push(compiledTemplate);
module.push('module.exports = \'' + options.name + '\';');
}
return module.join('\n');
}
function end() {
var template = nunjucks.precompileString(data, options);
this.queue(buildModule(template));
this.queue(null);
}
return through(write, end);
}
module.exports = nunjucksify;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment