使用express-handlebars渲染页面遇ENOENT错误的技术求助
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/layoutsdirectory - 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 yourmain.hbsincludes 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
extnamesetting ensures all your template files use.hbsinstead of.handlebars, keeping your file names consistent.
内容的提问来源于stack exchange,提问作者Falyoun

