Multiple views directories with express-hbs

This article talks about how you can put views in multiple locations and still use Express 4's default view rendering pipeline.

When configuring the express-hbs view engine, you must specify the path for the views. This acts as the jumping off point for all views that will be used by the res.render method.

app.set('views', path.join(__dirname,'/views'));  

When you actually go to use the view, the view name becomes the file path, minus the root directory and the file extension. For example, if you had the following file structure:

/views/
/views/index.hbs
/views/news/
/views/news/index.hbs
/views/news/article1.hbs
/views/news/article2.hbs

You would render the views as follows:

res.render('index', {});  
res.render('news/index', {});  
res.render('news/article1', {});  
res.render('news/article2', {});  

So lets poke around under the covers of express and see how this magic is working.

Express 4 Rendering

If you dig into express/application.js the render method generates a new View by reading the application configs for view engine and views.

These config values get set when you create your application and configure express-hbs. In the case of the views config, you set it to the root path for your views.

The Express View will take these inputs and use the lookup function to resolve the path to the the view.

What's interesting about this, is that lookup uses path.resolve to combine the root path as specified in views config with the name of the template supplied in the render method.

For example, given the following scenarios...

  • views configured at the application level to/my-app/views
  • ext is configured to .hbs by express-hbs
  • name is supplied by render as index

These view template path would be resolve to:

/my-app/views/index.hbs

Multiple views directories

Because Express 4 is using path.resolve under the covers, we can use relative paths to link to alternate directories.

Consider the file structure below:

/views/index.hbs
/data/news/article1.hbs
/data/news/article2.hbs

If we have configured Express as follows:

app.set('views', path.join(__dirname,'/views'));  

we can still access the /data/news/* templates by rendering them with a relative path:

res.render('../data/news/article1', {});  

What other techniques have used to solve this problem?

comments powered by Disqus