You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用express-handlebars渲染页面遇ENOENT错误的技术求助

Fixing express-handlebars Layout Issues in Your Node.js/Express App

Let’s break down your problems with express-handlebars step by step and get everything working as expected.


1. Why the First Error Occurred (No Config Params)

When you call expressHbs() without any configuration, the library follows default conventions:

  • It looks for layout files in a views/layouts directory
  • It expects a default layout file named main.handlebars

The error ENOENT: no such file or directory, open '...views\layouts\main.handlebars' simply means you hadn’t set up this required directory or file yet.


2. Fixing the Second Error (Custom Layouts Dir)

When you set layoutsDir: path.join(__dirname, "views"), you told express-handlebars to look for layouts directly in the views folder instead of views/layouts. But it still tried to load a default layout named main (using the .hbs extension you specified). Since you didn’t have a main.hbs in your views folder, it threw the second missing file error.


3. Correct Configuration for Layouts

First, let’s set up a clean, standard directory structure for your views (this will avoid confusion down the line):

views/
├── layouts/
│   └── main.hbs       # Your default shared layout
├── shop.hbs           # Shop page template
├── 404.hbs            # 404 error page template
└── admin/
    └── add-product.hbs # Admin add-product page template

Now update your app.js configuration to match this structure:

const express = require("express");
const bodyParser = require("body-parser");
const path = require("path");
const pp = require("./util/path.js");
const adminRoutes = require("./routes/admin");
const shopRoutes = require("./routes/shop");
const expressHbs = require("express-handlebars");

const app = express();

// Configure express-handlebars properly
app.engine("hbs", expressHbs({
  extname: "hbs",               // Use .hbs as the file extension for all templates
  layoutsDir: path.join(__dirname, "views", "layouts"), // Where layout files are stored
  defaultLayout: "main",        // Default layout to use (filename without extension)
  partialsDir: path.join(__dirname, "views", "partials") // Optional: for reusable template snippets
}));

app.set("view engine", "hbs");
app.set("views", "views");

app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, "public")));

app.use("/admin", adminRoutes.routes);
app.use(shopRoutes);

// Example: Disable layout for the 404 page
app.use((req, res, next) => {
 res.status(404).render("404", { 
   pageTitle: "Page Not Found",
   layout: false // Tells handlebars not to use the default layout
 });
});

app.listen(3001, "localhost", () => console.log("Listening on 3001 PORT"));

4. Fixing "All Pages Show Default Layout"

When you set defaultLayout, every render() call will use that layout unless you explicitly override it. Here’s how to customize this:

Option 1: Disable Layout for a Specific Page

If you don’t want a page to use any layout (like your 404 page), add layout: false to the render options:

res.render("404", {
  pageTitle: "Page Not Found",
  layout: false
});

Option 2: Use a Different Layout for a Page

Create a new layout file in views/layouts (e.g., admin-layout.hbs), then specify it in the render call:

// In your admin routes, when rendering the add-product page
res.render("admin/add-product", {
  pageTitle: "Add Product",
  layout: "admin-layout" // Matches admin-layout.hbs in the layouts directory
});

Option 3: Override Default Layout for an Entire Route Group

If an entire set of routes should use a unique layout, you can set a middleware to inject the layout option, but the simplest approach is to specify it in each render() call as shown above.


Key Notes About express-handlebars Layouts

  • Layout files use {{{body}}} as a placeholder where your page template content will be inserted. Make sure your main.hbs includes this:
    <!-- views/layouts/main.hbs -->
    <!DOCTYPE html>
    <html>
    <head>
      <title>{{pageTitle}}</title>
      <link rel="stylesheet" href="/css/styles.css">
    </head>
    <body>
      {{{body}}} <!-- This is where your page-specific content gets injected -->
    </body>
    </html>
    
  • The extname setting ensures all your template files use .hbs instead of .handlebars, keeping your file names consistent.

内容的提问来源于stack exchange,提问作者Falyoun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:02:19