express-handlebars isn't finding my layouts or partials
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");
});
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, 2022Comments
-
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 mylayout.hbs
. I don't get any errors or anything. It just doesn't use the layout even thoughlayout
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
orpartialsDir
? It's just not seeing them at all or something. And how comedefaultLayout
wasn't being used? I had to specify the layout. -
Jake Wilson about 8 yearsI renamed everything to
.handlebars
and removedhbs
references in my code. No change to my results. -
James Bubb about 8 yearsI 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 about 8 yearsOkay 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 almost 5 yearsFor anyone curious why this works, it's the difference between app.engine('handlebars',... and app.engine('hbs', ...
-
Jake Wilson over 4 yearsI 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. Theynpm install
and now everything breaks because that one dependency is now up to version13.5.3
, and is completely different than version1.0
was, that your application was written specifically to utilize. Semver standards exists for a reason.