Search code examples
javascriptnode.jsexpressswig-template

Conditional extend tag for Swig with Express.js and Node.js


Does anyone know how to make the extend tag for the Swig templating engine conditional or able to use a passed variable.

Instead of this:

{% extends '../layouts/layout.view' %}

I would like to do this

{% extends layout %}

Whilst rendering the file with this in express.js

res.render('jobs/index', { title: 'Jobs', layout: '../layouts/layout.view' });

Anyone did this before? Make the template extension conditional or pass a variable instead of a string. Help is much appreciated.


Solution

  • I managed to solve this. At least I got what I wanted by changing a couple of lines.

    What the solution essentially does is pass the locals parameter from the renderFile function to the compileFile function as such:

      this.renderFile = function (pathName, locals, cb) {
        if (cb) {
          exports.compileFile(pathName, locals, function (err, fn) { 
            if (err) {
              cb(err);
              return; 
           }
           cb(null, fn(locals));
         });
         return;
       }
    
       return exports.compileFile(pathName, locals)(locals);
     };
    

    This happens on line 514 and line 524 of the /lib/swig.js file. Locals essentially becomes options

    Then I only added this at line 405 in the same file

    if(options.layout) 
      parentName = options.layout;
    

    Whilst calling the res.render command in the route definition of express, I just add a layout option with the relative location of the layout.

    res.render('index', { title: 'Express', layout: 'layouts/main.layout' });
    

    This solved the problem for me completely. Maintaining normal {% extend %} functionality (when not overriding it with the layout option) whilst being able to set the layout dynamically.

    The only drawback is that layout becomes a reserved option, you could refactor this to not be a problem I think.

    Hope this helps someone. Two line changes and two lines of code made dynamic layouts possible for me. The performance is the same.