Skip to content

EJS Layouts: Tổ chức giao diện gọn gàng hơn trong Express.js

Khi mới bắt đầu xây dựng ứng dụng web với Express + EJS, hầu hết mọi người đều bắt đầu với Partials — tách header, footer, sidebar ra thành các file riêng rồi include vào từng trang.
Trông có vẻ ổn, cho đến khi bạn có 10 trang, và mỗi trang đều bắt đầu như thế này:
<!-- views/pages/letters.ejs -->
<%- include('../partials/header') %>
<%- include('../partials/topbar') %>
<%- include('../partials/sidebar') %>

<main>
<!-- nội dung trang -->
</main>

<%- include('../partials/footer') %>
Vấn đề chưa dừng ở đó. Khi cần thêm một thẻ <script> riêng cho một trang, bạn phải nhét nó vào footer partial — và script đó sẽ load ở mọi trang, dù chỉ cần ở một trang duy nhất.
Layouts giải quyết cả hai vấn đề này.

Layout là gì?

Thay vì mỗi view tự include các partial, layout là khung HTML bao ngoài — nó đã chứa sẵn header, footer, sidebar. View của bạn chỉ cần cung cấp phần nội dung thay đổi, layout sẽ tự điền vào đúng chỗ.
Hình dung đơn giản:
Partials approach: Layout approach:
───────────────── ──────────────────
view tự include layout bao ngoài view
→ header layout chứa: header
→ topbar topbar
→ sidebar sidebar
→ [nội dung] view chỉ chứa: [nội dung]
→ footer footer
Package phổ biến nhất để dùng Layouts với Express + EJS là express-ejs-layouts.

Cài đặt & Cấu hình

npm install express-ejs-layouts
// app.js
const express = require('express');
const expressLayouts = require('express-ejs-layouts');

const app = express();

app.set('view engine', 'ejs');
app.set('views', './views');

app.use(expressLayouts);
app.set('layout', 'layouts/main'); // layout mặc định cho toàn app
Chỉ vậy thôi. Từ giờ, mọi res.render() sẽ tự động dùng layouts/main.ejs làm khung.

Cấu trúc thư mục

views/
├── layouts/
│ ├── main.ejs ← 2-column (sidebar + content)
│ └── auth.ejs ← centered box (login, signup...)
├── partials/
│ ├── topbar.ejs
│ ├── sidebar.ejs
│ └── footer.ejs
└── pages/
├── home.ejs
├── letters.ejs
└── signin.ejs

Viết Layout đầu tiên

Layout chính: 2-column (layouts/main.ejs)

<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<title><%= typeof title !== 'undefined' ? title : 'My App' %></title>
<link rel="stylesheet" href="/css/app.css">
</head>
<body>
<%- include('../partials/topbar') %>

<div class="layout-2col">
<aside class="sidebar">
<%- include('../partials/sidebar') %>
</aside>

<main class="content">
<%- body %>
</main>
</div>

<%- include('../partials/footer') %>
</body>
</html>
<%- body %> là từ khóa quan trọng nhất — đây là chỗ express-ejs-layouts sẽ đặt nội dung từ view của bạn vào. Không có dòng này, layout sẽ không hiển thị gì cả.

Layout phụ: Centered box (layouts/auth.ejs)

Dùng cho các trang đăng nhập, đăng ký, xác nhận email — không cần topbar hay sidebar.
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<title><%= typeof title !== 'undefined' ? title : 'My App' %></title>
<link rel="stylesheet" href="/css/app.css">
</head>
<body class="auth-page">
<div class="auth-wrapper">
<div class="auth-box">
<%- body %>
</div>
</div>
</body>
</html>
Want to print your doc?
This is not the way.
Try clicking the ··· in the right corner or using a keyboard shortcut (
CtrlP
) instead.