Vidar S. Ramdal
Vidar S. Ramdal

Reputation: 1242

How can I extend Jade templates that are not stored on disk?

I am writing a small CMS application using NodeJS and Jade. For various reasons I want to store my Jade template files in a database (e.g. MongoDB), not on disk.

This works fine for a simple, self-contained Jade template: I can simply fetch the Jade string from the database, and jade.compile it.

However, if the template extends another template, I seem to be forced into storing my templates on disk. From jade.js:

  parseExtends: function(){
    var fs = _dereq_('fs');

    var path = this.resolvePath(this.expect('extends').val.trim(), 'extends');
    if ('.jade' != path.substr(-5)) path += '.jade';

    var str = fs.readFileSync(path, 'utf8');
    ...

So the extends keyword explicitly assumes the extended template is stored on disk.

What is the easiest way to let my Jade templates extend other templates that are stored in a database - or any other repository?

Upvotes: 1

Views: 317

Answers (1)

Vidar S. Ramdal
Vidar S. Ramdal

Reputation: 1242

It seems that this can be accomplished by overriding parseExtends and parseImports.

However, you will need some kind of synchronous storage, as Jade does all compilation synchronously. That is, no callbacks.

I eventually "solved" this by prefetching all templates and storing them in a templateMap object:

{
  "path": "/templates/frontpage.jade",
  "content": "<html><body>Here's some Jade</body></html>"
},
...

Then overriding parseExtends and parseImports so that they look for the template path in templateMap, not on disk:

jade.Parser.prototype.parseExtends = function () {
    var path = this.expect('extends').val.trim();
    path = Path.normalize(path).replace("\\", "/"); // Necessary on Windows
    var self = this;
    var str = templatesMap[path];
    if (!str) {
        return callback(new RendererError("Could not find template " + path));
    }
    var parser = new this.constructor(str, path, this.options);

    parser.blocks = this.blocks;
    parser.contexts = this.contexts;
    self.extending = parser;
    return new Nodes.Literal('');
}

Upvotes: 3

Related Questions