express-handlebars isn't finding my layouts or partials

12,173

According to the API documentation for express-handlebars if you are changing the file extension from the default .handlebars then when you set the view engine, all occurrences of handlebars should be replaced with the new extension you wish to use.

So your express setup will need to be updated to:

app.engine('hbs', handlebars.engine);
app.set('view engine', 'hbs');
app.set('views', path.join(__dirname, "views"));

Note: the documentation uses a period before the extension e.g. .hbs but it seems to work without this.

Full code:

var path = require('path');
var express = require('express');
var app = express();
var http = require('http').Server(app);

var handlebars = require('express-handlebars').create({
  layoutsDir: path.join(__dirname, "views/layouts"),
  partialsDir: path.join(__dirname, "views/partials"),
  defaultLayout: 'layout',
  extname: 'hbs'
});

app.engine('hbs', handlebars.engine);
app.set('view engine', 'hbs');
app.set('views', path.join(__dirname, "views"));

app.get('/', function(req, res){
  res.render('index');
});


http.listen(3000, function(){
  console.log("Server running");
});
Share:
12,173
Jake Wilson
Author by

Jake Wilson

Experienced in developing tools for 3D animation, motion capture, video game and movie production, web development, Android development, responsive design, etc...

Updated on June 04, 2022

Comments

  • Jake Wilson
    Jake Wilson about 2 years

    I have the following Express 4 view engine setup:

    var handlebars = require('express-handlebars').create({
      layoutsDir: path.join(__dirname, "views/layouts"),
      partialsDir: path.join(__dirname, "views/partials"),
      defaultLayout: 'layout',
      extname: 'hbs'
    });
    
    app.engine('handlebars', handlebars.engine);
    app.set('view engine', 'hbs');
    app.set('views', path.join(__dirname, "views"));
    

    I have the following file structure:

    /views
        error.hbs
        index.hbs
        /partials
            menu.hbs
        /layouts
            layout.hbs
    

    And finally in my route: res.render('index');

    And visiting my site, it loads only my index.hbs template. It does not use my layout.hbs. I don't get any errors or anything. It just doesn't use the layout even though layout is set as my default layout in the handlebars config.

    Next I tried to change my code to this:

    res.render('index', {layout: 'layout'});

    Now I get the error:

    Error: ENOENT: no such file or directory, open '/.../views/layout.hbs'

    So it's like it's not finding my layoutsDir... What am I missing here?

    Next I changed it to this:

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

    Okay so that worked. My layout is now loaded. But then I added in a partial to my layout:

    {{> menu }}

    Now I get: /.../views/index.hbs: The partial menu could not be found

    So what is going on here? How come Handlebars isn't recognizing my layoutsDir or partialsDir? It's just not seeing them at all or something. And how come defaultLayout wasn't being used? I had to specify the layout.

  • Jake Wilson
    Jake Wilson about 8 years
    I renamed everything to .handlebars and removed hbs references in my code. No change to my results.
  • James Bubb
    James Bubb about 8 years
    I updated my post with the full code I used to verify this earlier. Can you spot any differences? You restarted your app after making the changes right? :)
  • Jake Wilson
    Jake Wilson about 8 years
    Okay for some reason it's working now once I renamed everything to .hbs and used your code. Not sure exactly what the difference was previously. Yes I was restarting Node each time. Thank you,
  • Brian Burton
    Brian Burton almost 5 years
    For anyone curious why this works, it's the difference between app.engine('handlebars',... and app.engine('hbs', ...
  • Jake Wilson
    Jake Wilson over 4 years
    I would not recommend using a pure wildcard in NPM dependencies. Let's say you develop an application that uses version 1.0 of some random dependency. Then 5 years later another person comes along and wants to develop your app. They npm install and now everything breaks because that one dependency is now up to version 13.5.3, and is completely different than version 1.0 was, that your application was written specifically to utilize. Semver standards exists for a reason.