Skip to content

Commit

Permalink
Improve CommonJS modules
Browse files Browse the repository at this point in the history
Compiling a template as a CommonJS module returns a function that must be hydrated with a Dust:

    var tmpl = require('./my/tmpl.js')(dust);

Once you have a handle on that object, you can either invoke it directly:

    tmpl(context, function(err, out) { ... })
    tmpl(context).on('data', ...)

Or you can pass it to `dust.render`:

    dust.render(tmpl, ...)

Or you can access the compiled template if you need to do something with it:

    tmpl.template; // function body_0(chunk, context, bodies, params) { ... }
  • Loading branch information
Seth Kinast committed Apr 15, 2015
1 parent 7775a86 commit 815cfc9
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 17 deletions.
15 changes: 13 additions & 2 deletions Gruntfile.js
Expand Up @@ -181,6 +181,17 @@ module.exports = function(grunt) {
}
},
jasmine_nodejs: {
cjs: {
specs: ['test/jasmine-test/spec/cjsSpec.js'],
options: {
reporters: {
console: {
colors: false,
verbose: false
}
}
}
},
dustc: {
specs: ['test/jasmine-test/spec/cli/*'],
options: {
Expand Down Expand Up @@ -286,11 +297,11 @@ module.exports = function(grunt) {
grunt.registerTask('build', ['clean:build', 'shell:buildParser', 'buildLib', 'uglify']);

//test tasks
grunt.registerTask('testNode', ['shell:oldTests']);
grunt.registerTask('testNode', ['jasmine_nodejs:cjs', 'shell:oldTests']);
grunt.registerTask('testRhino', ['build', 'shell:testRhino']);
grunt.registerTask('testPhantom', ['build', 'jasmine:testProd']);
grunt.registerTask('testCli', ['build', 'jasmine_nodejs:dustc']);
grunt.registerTask('test', ['build', 'jasmine:testProd', 'jasmine_nodejs:dustc', 'shell:oldTests', 'shell:testRhino', 'jasmine:coverage']);
grunt.registerTask('test', ['build', 'jasmine:testProd', 'jasmine_nodejs:dustc', 'jasmine_nodejs:cjs', 'shell:oldTests', 'shell:testRhino', 'jasmine:coverage']);

//task for debugging in browser
grunt.registerTask('dev', ['build', 'jasmine:testDev:build', 'connect:testServer','log:testClient', 'watch:lib']);
Expand Down
31 changes: 17 additions & 14 deletions lib/compiler.js
Expand Up @@ -163,7 +163,8 @@
escapedName = dust.escapeJs(name),
AMDName = name? '"' + escapedName + '",' : '',
compiled = 'function(dust){',
entry = compiler.compileNode(context, ast);
entry = compiler.compileNode(context, ast),
iife;

if(name) {
compiled += 'dust.register("' + escapedName + '",' + entry + ');';
Expand All @@ -173,12 +174,17 @@
compileBodies(context) +
'return ' + entry + '}';

iife = '(' + compiled + '(dust));';

if(dust.config.amd) {
return 'define(' + AMDName + '["dust.core"],' + compiled + ');';
} else if(dust.config.cjs) {
return 'module.exports=' + compiled;
return 'module.exports=function(dust){' +
'var tmpl=' + iife +
'var f=' + loaderFor().toString() + ';' +
'f.template=tmpl;return f}';
} else {
return '(' + compiled + '(dust));';
return iife;
}
}

Expand Down Expand Up @@ -432,21 +438,18 @@

function renderSource(source, context, callback) {
var tmpl = dust.loadSource(dust.compile(source));
if(callback) {
return dust.render(tmpl, context, callback);
} else {
return dust.stream(tmpl, context);
}
return loaderFor(tmpl)(context, callback);
}

function compileFn(source, name) {
var tmpl = dust.loadSource(dust.compile(source, name));
return function(context, callback) {
if(callback) {
return dust.render(tmpl, context, callback);
} else {
return dust.stream(tmpl, context);
}
return loaderFor(tmpl);
}

function loaderFor(tmpl) {
return function load(ctx, cb) {
var fn = cb ? 'render' : 'stream';
return dust[fn](tmpl, ctx, cb);
};
}

Expand Down
13 changes: 12 additions & 1 deletion lib/dust.js
Expand Up @@ -121,7 +121,18 @@
dust.cache = {};
}

var tmpl = dust.isTemplateFn(nameOrTemplate) ? nameOrTemplate : dust.cache[nameOrTemplate];
var tmpl;
if(typeof nameOrTemplate === 'function' && nameOrTemplate.template) {
// Sugar away CommonJS module templates
tmpl = nameOrTemplate.template;
} else if(dust.isTemplateFn(nameOrTemplate)) {
// Template functions passed directly
tmpl = nameOrTemplate;
} else {
// Load a template with this name from cache
tmpl = dust.cache[nameOrTemplate];
}

if (tmpl) {
return tmpl(chunk, Context.wrap(context, tmpl.templateName));
} else {
Expand Down
59 changes: 59 additions & 0 deletions test/jasmine-test/spec/cjsSpec.js
@@ -0,0 +1,59 @@
/*global describe,expect,it,beforeEach */
/*jshint evil:true*/
var dust = require('../../../');

function load(tmpl) {
dust.config.cjs = true;
return eval(dust.compile(tmpl, 'hello'))(dust);
}

describe('CommonJS template', function() {
var template = "Hello {world}!",
context = { world: "world" },
rendered = "Hello world!",
templateName = 'hello',
tmpl;

beforeEach(function() {
tmpl = load(template);
});

it('can be invoked to render', function() {
tmpl(context, function(err, out) {
expect(out).toEqual(rendered);
});
});

it('can be invoked to stream', function(done) {
tmpl(context).on('data', function(out) {
expect(out).toEqual(rendered);
done();
});
});

it('can be passed to dust.render', function() {
dust.render(tmpl, context, function(err, out) {
expect(out).toEqual(rendered);
});
});

it('can be passed to dust.stream', function(done) {
dust.stream(tmpl, context).on('data', function(out) {
expect(out).toEqual(rendered);
done();
});
});

it('has a template property that can be passed to dust.render', function() {
expect(tmpl.template.templateName).toEqual(templateName);
dust.render(tmpl.template, context, function(err, out) {
expect(out).toEqual(rendered);
});
});

it('has a name that can be passed to dust.render', function() {
dust.render(templateName, context, function(err, out) {
expect(out).toEqual(rendered);
});
});
});
1 change: 1 addition & 0 deletions test/jasmine-test/spec/cli/cliSpec.js
@@ -1,3 +1,4 @@
/*global describe,expect,it,afterEach */
var path = require('path'),
fs = require('fs'),
exec = require('child_process').exec;
Expand Down

0 comments on commit 815cfc9

Please sign in to comment.