引言
当你使用 Express 构建 Node.js 应用程序时,你经常需要一种方法来生成 HTML 页面,而无需在每个路由中复制粘贴相同的标记。模板引擎可以帮助你保持 HTML 的组织性,同时仍然渲染动态内容。
Express 支持多种模板引擎。一个受欢迎的选择是 Embedded JavaScript templates (EJS),它允许你直接在 HTML 模板中嵌入 JavaScript,从而让服务器在发送页面到浏览器之前渲染完整的页面。
在本教程中,你将学习如何使用 Express 设置 EJS,创建并渲染 EJS 视图,使用 partials 复用标记,以及从路由向模板传递数据以渲染变量和列表。
使用 App Platform 从 GitHub 部署你的前端应用程序。让 专注于扩展你的应用。
关键要点:
- EJS 是用于 Node.js 应用程序的服务器端模板引擎。它允许开发者在 HTML 模板中嵌入 JavaScript,从而在将页面发送到浏览器之前在服务器上渲染动态内容。
- Express 通过
view engine设置与 EJS 集成。安装 EJS 后,你可以通过调用app.set('view engine', 'ejs')配置 Express 使用它,这使得路由可以使用res.render()渲染.ejs模板。 - 模板默认存储在
views目录中。Express 会自动在views文件夹中查找模板文件,这有助于以一致的项目结构组织模板、partials 和页面特定视图。 - Partials 允许你复用常见的模板组件。共享元素如头部、导航栏和页脚可以放在 partial 模板中,并使用
include()指令包含在多个页面中。 - 布局和 partial 组合有助于维护一致的页面结构。尽管 EJS 不包含内置的布局块,但开发者可以通过在模板中组合共享 partials 来创建类似布局的结构。
- 动态数据可以从 Express 路由传递到 EJS 模板。
res.render()方法接受一个包含变量、数组或对象的数据对象,这些数据随后可以在模板中访问。 - EJS 提供不同的模板标签用于逻辑和输出。
<% %>执行 JavaScript 逻辑,<%= %>输出转义的 HTML 以确保安全,<%- %>输出原始 HTML 用于可信内容,如 partial 模板。 - EJS 对于服务器渲染的 Web 应用程序很有用,但与现代前端框架不同。虽然 EJS 在服务器上生成 HTML,但像 React 和 Vue 这样的框架通常使用基于组件的架构在浏览器中管理 UI 渲染。
前提条件
如果你想跟随本文学习,你需要:
- 一个用于 Node.js 的本地开发环境。请参考 如何安装 Node.js 并创建本地开发环境。
本教程已在 Node v24.14.0、npm v11.9.0、express v5.1.0 和 ejs v5.0.1 上验证。
步骤 1 — 设置项目
首先,打开终端窗口并创建一个新的项目目录:
- mkdir ejs-demo
然后,导航到新创建的目录:
- cd ejs-demo
此时,你可以初始化一个新的 npm 项目:
- npm init -y
接下来,你需要安装 express 包:
- npm install express
然后安装 ejs 包:
- npm install ejs
此时,你已经有一个新的项目,可以使用 Express 和 EJS 了。
步骤 2 — 使用 server.js 进行配置
server.js 进行配置所有依赖项安装完成后,让我们配置应用以使用 EJS,并为首页和关于页面设置路由。
创建一个新的 server.js 文件,用你的代码编辑器打开它,并添加以下代码:
const express = require('express');
const app = express();
// 设置视图引擎为 ejs
app.set('view engine', 'ejs');
// 使用 res.render 来加载 ejs 视图文件
// 首页
app.get('/', function(req, res) => {
res.render('pages/index');
});
// 关于页面
app.get('/about', function(req, res) => {
res.render('pages/about');
});
app.listen(8080, () => console.log('Server is listening on port 8080'));
这段代码定义了应用并在 8080 端口上监听。
这段代码还使用以下方式将 EJS 设置为 Express 应用的视图引擎:
app.set('view engine', 'ejs');
注意代码是如何使用 res.render() 将视图发送给用户的。需要注意的是,res.render() 会在 views 文件夹中查找视图。因此你只需要定义 pages/index,因为完整路径是 views/pages/index。
接下来,你将使用 EJS 创建视图。
步骤 3 — 创建 EJS Partials
像你构建的许多应用程序一样,会有很多被重用的代码。这些被称为partials。在本例中,将有三个 partials 在 Index 页面和 About 页面上被重用:head.ejs、header.ejs 和 footer.ejs。现在让我们创建这些文件。
创建一个新的 views 目录:
- mkdir views
然后,创建一个新的 partials 子目录:
- mkdir views/partials
在这个目录中,创建一个新的 head.ejs 文件,并用你的代码编辑器打开它。添加以下代码行:
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>EJS Is Fun</title>
<!-- CSS (从 CDN 加载 bootstrap) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css">
<style>
body { padding-top:50px; }
</style>
这段代码包含了 HTML 文档 head 的元数据。它还包含了 Bootstrap 样式。
接下来,创建一个新的 header.ejs 文件,并用你的代码编辑器打开它。添加以下代码行:
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="/">EJS Is Fun</a>
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/about">About</a>
</li>
</ul>
</nav>
这段代码包含了 HTML 文档的导航,并使用 Bootstrap 的几个 class 进行样式化。
接下来,创建一个新的 footer.ejs 文件,并用你的代码编辑器打开它。添加以下代码行:
<p class="text-center text-muted">© Copyright 2026 The Awesome People</p>
这段代码包含版权信息,并使用 Bootstrap 的几个 class 进行样式化。
EJS 中的 Partials 与 Layouts
在服务器渲染的应用程序中,partials 和 layouts 都能帮助你避免重复的标记,但它们解决的问题略有不同。
partial 是一个小的、可重用的模板片段。例如,你可以为 header、footer 或导航栏创建一个 partial,然后在需要的地方包含它,这样只需在一个地方维护标记。
layout 是一个页面级别的包装器,为多个页面定义共享结构。典型的 layout 包括整体 HTML 骨架(如 <!doctype html>、共享的 <head> 以及一致的 header 和 footer),并为每个页面留出空间提供其主要内容。
EJS 支持 子模板包含,这就是你为 head.ejs、header.ejs 和 footer.ejs 所使用的。根据 EJS 文档,包含是相对于当前模板的,通常在使用包含其他模板时使用原始输出标签 (<%-),以避免对包含的 HTML 输出进行双重转义。
EJS 还指出它不专门支持“blocks”,但你仍然可以通过组合共享的包含来实现 layout 模式。例如,你可以在每个页面的顶部包含 header,在底部包含 footer,并将每个页面的独特内容放在中间。
在本教程中,你使用 partials 的方式也产生了类似 layout 的效果:每个页面(index.ejs 和 about.ejs)都包含相同的 head、header 和 footer,从而创建一致的页面结构。
如果你以后想要更强的“单一 layout 文件”方法,可以探索 Express middleware 或第三方 helper,它们在 EJS 之上实现了 layout/block 行为。有关 Express 如何通过 app.set('view engine', ...) 和 res.render() 集成模板引擎的背景信息,请参阅 Express 关于使用模板引擎的指南。
接下来,你将在 index.ejs 和 about.ejs 中使用这些 partials。
步骤 4 — 将 EJS 部分模板添加到视图中
你已经定义了三个 partials。现在你可以在视图中使用 include 来包含它们。
使用 <%- include('RELATIVE/PATH/TO/FILE') %> 在另一个文件中嵌入 EJS partial。
- 当你希望 EJS 输出未转义内容时,使用连字符
<%-而不是<%。 - partial 的路径是相对于当前文件的相对路径。
- 在模板中使用
<%=(转义输出)处理用户控制的数据,并将<%-(未转义输出)保留给你明确信任的内容。
然后,创建一个新的 pages 子目录:
- mkdir views/pages
在这个目录中,创建一个新的 index.ejs 文件并用代码编辑器打开它。添加以下代码行:
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('../partials/head'); %>
</head>
<body class="container">
<header>
<%- include('../partials/header'); %>
</header>
<main>
<div class="p-5 mb-4 bg-light rounded-3">
<h1>This is great</h1>
<p>Welcome to templating using EJS</p>
</div>
</main>
<footer>
<%- include('../partials/footer'); %>
</footer>
</body>
</html>
保存此文件更改,然后运行应用程序:
- node server.js
如果你在网页浏览器中访问 http://localhost:8080/,你可以看到 Index 页面:
接下来,创建一个新的 about.ejs 文件并用代码编辑器打开它。添加以下代码行:
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('../partials/head'); %>
</head>
<body class="container">
<header>
<%- include('../partials/header'); %>
</header>
<main>
<div class="row">
<div class="col-sm-8">
<div class="p-5 mb-4 bg-light rounded-3">
<h1>This is great</h1>
<p>Welcome to templating using EJS</p>
</div>
</div>
<div class="col-sm-4">
<div class="card p-3">
<h3>Look I'm A Sidebar!</h3>
</div>
</div>
</div>
</main>
<footer>
<%- include('../partials/footer'); %>
</footer>
</body>
</html>
这段代码添加了一个 Bootstrap 侧边栏,以演示 partials 如何结构化以在不同模板和页面中重用。
保存此文件更改,然后运行应用程序:
- node server.js
如果你在网页浏览器中访问 http://localhost:8080/about,你可以看到带有侧边栏的 About 页面:
现在你可以使用 EJS 从 Node 应用程序向视图传递数据了。
步骤 5 — 向视图和部分模板传递数据
让我们定义一些基本变量和列表,并传递给 Index 页面。
在代码编辑器中重新打开 server.js,并在 app.get('/') 路由内部添加以下代码行:
const express = require('express');
const app = express();
// 设置视图引擎为 ejs
app.set('view engine', 'ejs');
// 使用 res.render 来加载 ejs 视图文件
// index 页面
app.get('/', function(req, res) => {
const mascots = [
{ name: 'Sammy', organization: "", birth_year: 2012},
{ name: 'Tux', organization: "Linux", birth_year: 1996},
{ name: 'Moby Dock', organization: "Docker", birth_year: 2013}
];
const tagline = "No programming concept is complete without a cute animal mascot.";
res.render('pages/index', {
mascots: mascots,
tagline: tagline
});
});
// about 页面
app.get('/about', function(req, res) => {
res.render('pages/about');
});
app.listen(8080, () => console.log('Server is listening on port 8080'));
这段代码定义了一个名为 mascots 的数组和一个名为 tagline 的字符串。接下来,我们在 index.ejs 中使用它们。
在 EJS 中渲染单个变量
要输出单个变量,可以使用 <%= tagline %>。
在代码编辑器中重新打开 index.ejs,并添加以下代码行:
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('../partials/head'); %>
</head>
<body class="container">
<header>
<%- include('../partials/header'); %>
</header>
<main>
<div class="p-5 mb-4 bg-light rounded-3">
<h1>This is great</h1>
<p>Welcome to templating using EJS</p>
<h2>变量</h2>
<p><%= tagline %></p>
</div>
</main>
<footer>
<%- include('../partials/footer'); %>
</footer>
</body>
</html>
这段代码将在 Index 页面上显示 tagline 的值。
XSS 转义
当你将动态值渲染到 HTML 中时,应该考虑跨站脚本攻击 (XSS)。XSS 发生在不受信任的数据被浏览器解释为代码而不是文本时。
EJS 提供了两种行为不同的输出标签:
<%=输出带有 EJS 转义的值(EJS 文档中默认描述为转义 XML/HTML 特殊字符)。<%-输出未转义的值,这意味着它作为原始标记插入到响应中。
在实践中,这意味着对于任何可能来自用户、URL 参数、数据库或其他外部系统的值,都应该使用 <%=:
<p><%= tagline %></p>
如果你使用 <%-,你就告诉 EJS 将该值视为可信的 HTML:
<p><%- tagline %></p>
只有在有意渲染原始 HTML 并且信任(或已安全清理)你插入的字符串时,才使用 <%- ... %>。例如,EJS 文档建议对 include 使用 <%- include(...) %>,以避免包含的模板 HTML 被再次转义。
还要记住,转义是依赖上下文的。在将值插入普通 HTML 内容时,HTML 转义是正确的起点,但它不是适用于每个上下文的通用解决方案(例如,URL、内联 JavaScript 或内联 CSS)。OWASP 的 XSS 指南建议使用与数据插入上下文匹配的输出编码,并避免像直接将不受信任数据注入 <script> 块这样的“危险上下文”。
最后,请注意 EJS 项目的安全指南:EJS 执行 JavaScript,因此如果你将不受信任的输入直接传递到渲染中,你需要对结果负责。避免像将请求中的所有内容直接传递到渲染这样的模式:
app.get('/', (req, res) => {
res.render('index', req.query);
});
相反,显式传递你预期的值(并根据需要验证它们):
app.get('/', (req, res) => {
res.render('index', {
tagline: String(req.query.tagline || '')
});
});
将值转换为字符串不能替代验证。如果这些数据由用户控制,在渲染前考虑验证它(例如,通过强制最大长度或使用允许列表)。
更多详情,请参阅 EJS 文档中的标签部分以及 EJS 项目在 GitHub 页面上的安全指南。
有关 XSS 和上下文特定输出编码的更广泛的、框架无关的指南,请参阅 OWASP Cross Site Scripting Prevention Cheat Sheet。
在 EJS 中遍历数据
要遍历数据,可以使用 .forEach。
在代码编辑器中重新打开 index.ejs,并添加以下代码行:
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('../partials/head'); %>
</head>
<body class="container">
<header>
<%- include('../partials/header'); %>
</header>
<main>
<div class="p-5 mb-4 bg-light rounded-3">
<h1>This is great</h1>
<p>Welcome to templating using EJS</p>
<h2>变量</h2>
<p><%= tagline %></p>
<ul>
<% mascots.forEach(function(mascot) { %>
<li>
<strong><%= mascot.name %></strong>
代表 <%= mascot.organization %>,
诞生于 <%= mascot.birth_year %>
</li>
<% }); %>
</ul>
</div>
</main>
<footer>
<%- include('../partials/footer'); %>
</footer>
</body>
</html>
保存此文件更改,然后运行应用程序:
- node server.js
如果在网页浏览器中访问 http://localhost:8080/,你可以看到带有 mascots 的 Index 页面:
在 EJS 中向部分模板传递数据
EJS 部分模板可以访问与父视图相同的所有数据。但要小心。如果你在一部分模板中引用变量,它需要在每个使用该部分模板的视图中定义,否则会抛出错误。
你也可以在 include 语法中定义并向 EJS 部分模板传递变量,如下所示:
...
<header>
<%- include('../partials/header', {variant: 'compact'}); %>
</header>
...
但你需要再次小心假设变量已被定义。
如果你想在一部分模板中引用可能并非总是定义的变量,并为其提供默认值,可以这样做:
...
<em>变体:<%= typeof variant != 'undefined' ? variant : 'default' %></em>
...
在上面的行中,EJS 代码如果 variant 已定义则渲染其值,否则渲染 default。
EJS 与现代前端框架的比较
EJS 是一种模板引擎,帮助您在服务器端生成 HTML(例如,从 Express 路由处理器中使用 res.render())。现代前端框架如 React 和 Vue 是用于构建用户界面的 JavaScript 框架,它们鼓励基于组件的模型,其中 UI 被描述为数据和状态的函数。
这些工具可能有重叠,但通常用于不同类型的项目。要决定什么适合您的应用,有助于从几个实际维度进行比较。
-
渲染发生的位置:使用 EJS + Express 时,服务器渲染 HTML 文档并发送到浏览器,通常在每个请求上进行。使用 React 和 Vue 时,您从组件构建 UI,并基于 JavaScript state 进行渲染。React 组件是返回 markup 的 JavaScript 函数,而 Vue 将声明式模板与响应式系统结合,当 state 变化时更新 UI。
-
交互性如何管理:EJS 专注于生成 HTML,并不提供内置的响应式 UI 层。如果需要交互行为,您通常需要自己编写客户端 JavaScript(例如,添加事件监听器、获取数据并更新 DOM)。在 React 和 Vue 中,交互性是内置的:您更新 state,框架就会更新用户看到的内容。
-
路由和页面结构:EJS 常用于多页面应用,其中每个路由返回完整的 HTML 响应。相比之下,许多 React/Vue 应用被构建为单页面应用 (SPA),其中路由可以在客户端发生,页面在不完全重新加载的情况下更新。(这些框架也可以用于服务器渲染设置,但组件模型保持不变。)
-
工具链和构建流程:您可以使用 EJS 配合最少的工具链,因为服务器在运行时渲染模板。React 和 Vue 通常与构建工具一起使用(例如,用于打包 JavaScript 和编译框架特定语法,如 JSX 或 Vue 单文件组件)。这增加了复杂性,但也支持具有许多组件的大型应用。
-
性能和交付权衡:服务器渲染的 EJS 页面可以简单快速地交付,因为浏览器立即接收到 HTML。客户端为主的 React/Vue 应用可能会发送更多 JavaScript 以实现丰富的交互性,这对于高度动态的界面来说是值得的权衡。在实践中,您根据应用需求、交互程度以及服务器与浏览器之间工作负载的平衡来选择。
-
EJS 适合的场景:EJS 倾向于适用于服务器渲染页面、内容为主的网站、具有适度交互性的管理仪表板、原型以及希望保持前端简单并依赖标准 HTML、CSS 和 JavaScript 的应用。
-
React 或 Vue 适合的场景:React 和 Vue 更适合高度交互性的应用,这些应用具有复杂的 UI state、丰富的客户端行为以及组件驱动的界面,其中页面的许多部分会响应用户输入而更新。
您也可以混合使用这些方法。例如,您可以使用 EJS 渲染页面的大部分内容,然后仅在需要更丰富交互性的地方添加少量客户端 JavaScript(或在页面的一部分嵌入框架组件)。
如果您想深入了解,请参考 Express 关于模板引擎的指南、React 文档以及 Vue 介绍。
排查常见的 EJS 错误
在 Express 应用程序中使用 EJS 时,你可能会遇到与模板路径、语法错误或未定义变量相关的错误。了解这些常见问题及其解决方法,可以帮助你在开发过程中快速调试问题。
错误:Failed to lookup view
最常见的错误之一是 Express 无法找到你尝试渲染的模板文件。
典型的错误信息可能如下所示:
Error: Failed to lookup view "pages/index" in views directory
这通常由以下原因之一引起:
- 模板文件不存在于预期的目录中。
views目录配置错误。- 文件扩展名不正确。
默认情况下,Express 在名为 views 的目录中查找模板。当你这样渲染模板时:
res.render('pages/index');
Express 会在以下路径查找文件:
views/pages/index.ejs
要修复此问题:
- 确认文件存在于正确的路径。
- 确保文件扩展名为
.ejs。 - 验证项目中包含
views目录。
如果你的模板存储在其他目录中,你可以配置 Express 使用自定义路径:
app.set('views', path.join(__dirname, 'templates'));
这会告诉 Express 在 templates 目录中查找模板,而不是 views。
错误:Unexpected token 或模板语法错误
EJS 模板允许你在 HTML 中嵌入 JavaScript。如果模板中的 JavaScript 语法无效,EJS 会抛出语法错误。
例如,这个模板包含一个错误:
<ul>
<% mascots.forEach(function(mascot) { %>
<li><%= mascot.name %></li>
</ul>
循环缺少闭合标签。
正确的版本应该包含闭合语句:
<ul>
<% mascots.forEach(function(mascot) { %>
<li><%= mascot.name %></li>
<% }); %>
</ul>
调试语法错误时:
- 检查每个
<%标签都有匹配的%>。 - 确保循环和条件语句正确闭合。
- 验证嵌入的 JavaScript 语法有效。
因为 EJS 在模板中执行 JavaScript,语法错误的行为类似于普通的 JavaScript 错误。
错误:Cannot read property of undefined
另一个常见问题是模板尝试访问未传递给视图的变量。
例如,这个模板期望一个名为 tagline 的变量:
<p><%= tagline %></p>
如果路由没有提供该变量:
res.render('pages/index');
EJS 会抛出错误,因为 tagline 未定义。
要修复此问题,确保在渲染模板时传递变量:
res.render('pages/index', {
tagline: "Welcome to my site"
});
你也可以在模板中提供备用值:
<p><%= typeof tagline !== 'undefined' ? tagline : 'Default message' %></p>
这可以防止变量缺失时出现错误。
错误:不正确的 include 路径
使用 partials 时,传递给 include() 的路径必须相对于当前模板文件。
例如:
<%- include('../partials/header') %>
如果路径不正确,EJS 将无法加载模板。
常见错误包括:
- 使用错误的相对路径。
- 移动模板但未更新 include 路径。
- 忘记正确的文件夹结构。
如果你的项目结构如下所示:
views/
├── pages/
│ └── index.ejs
└── partials/
└── header.ejs
从 index.ejs 的正确 include 路径应该是:
<%- include('../partials/header') %>
如果 include 失败,请仔细检查相对路径。
错误:HTML 未正确渲染
有时模板会渲染出意外的 HTML,因为使用了错误的 EJS 输出标签。
EJS 提供了两种常见的输出标签:
| 标签 | 行为 |
|---|---|
<%= %> |
转义 HTML |
<%- %> |
输出原始 HTML |
如果你使用 <%= 渲染 HTML,HTML 将被转义并显示为文本。
示例:
<p><%= "<strong>Hello</strong>" %></p>
这会产生:
<strong>Hello</strong>
要正确渲染 HTML,请使用 <%- %>:
<p><%- "<strong>Hello</strong>" %></p>
但是,仅对可信内容使用 <%- %>,以避免跨站脚本攻击 (XSS) 漏洞。
错误:更改未在浏览器中显示
在开发过程中,你可能更新了模板但未在浏览器中看到更改。
这可能是由于以下原因:
- 浏览器缓存
- 服务器未重启
- Express 中的模板缓存
要解决此问题:
- 重启 Node.js 服务器
- 在开发期间禁用模板缓存:
app.set('view cache', false);
你也可以使用 nodemon 等工具,在文件更改时自动重启服务器。
常见问题解答
1. Node.js 中 EJS 用于什么?
Embedded JavaScript templates(EJS)用于在 Node.js 应用程序的服务器端生成动态 HTML。EJS 允许开发者使用特殊的标签如 <% %>、<%= %> 和 <%- %> 将 JavaScript 直接嵌入 HTML 模板中。
在典型的 Express 应用程序中,服务器通过将 EJS 模板与数据结合来渲染模板,并将生成的 HTML 发送到浏览器。例如,一个 Express route 可以将变量传递给模板并渲染完整的网页:
res.render('pages/index', { title: 'Home Page' });
这种方法被称为服务器端渲染 (SSR),常用于:
- 仪表板和管理面板
- 内容驱动的网站
- 需要 SEO 友好页面的应用程序
- 不需要大量客户端 JavaScript 的应用程序
因为 EJS 模板在服务器端处理,浏览器接收到的是完全渲染的 HTML。
2. EJS 适合生产环境应用程序吗?
是的,EJS 可以用于生产环境应用程序。它是一个轻量级的模板引擎,与 Express 和其他 Node.js 框架集成良好。
EJS 常用于:
- 内部工具和仪表板
- 服务器渲染的 Web 应用程序
- 内容驱动的网站
- 中小型 Node.js 项目
因为 EJS 使用纯 JavaScript 和 HTML,所以易于学习和维护。但是,对于具有高度交互界面的超大型应用程序,开发者通常会结合使用前端框架如 React 或 Vue 以及基于 API 的后端。
即使在这些环境中,EJS 仍然可以用于渲染服务器端页面,如登录界面、管理面板或初始 HTML 模板。
3. 如何向 EJS 模板传递数据?
通过 Express 中的 res.render() 函数向 EJS 模板传递数据。
res.render() 的第二个参数是一个对象,包含将在模板中可用的变量:
app.get('/', (req, res) => {
const message = "Welcome to my site";
res.render('pages/index', {
message: message
});
});
在 EJS 模板中,可以使用 <%= %> 标签访问该变量:
<p><%= message %></p>
你可以向模板传递任何 JavaScript 数据类型,包括:
- strings
- numbers
- objects
- arrays
模板可以使用标准的 JavaScript 语法遍历数组或访问对象属性。
4. EJS 和 Pug 有什么区别?
EJS 和 Pug 都是与 Node.js 和 Express 一起使用的模板引擎,但它们在语法和设计理念上有所不同。
EJS 使用带有嵌入 JavaScript 的标准 HTML,而 Pug 使用基于缩进的自定义语法来替换传统的 HTML 标签。
例如,在 EJS 中一个简单的标题如下所示:
<h1><%= title %></h1>
在 Pug 中的相同元素如下所示:
h1= title
一些关键区别如下:
| 特性 | EJS | Pug |
|---|---|---|
| Syntax | 标准 HTML | 基于缩进的自定义语法 |
| 学习曲线 | 对 HTML 开发者更简单 | 需要学习新语法 |
| 灵活性 | 使用普通 JavaScript | 使用 Pug 特定语法 |
| 可读性 | 熟悉的 HTML 结构 | 更简洁但不那么明确 |
喜欢直接使用 HTML 的开发者通常选择 EJS,而其他人则偏好 Pug 的简洁语法和内置模板功能。
5. EJS 可以在不使用 Express 的情况下工作吗?
是的。EJS 可以独立于 Express 使用。
虽然 EJS 通常作为 Express 应用程序的视图引擎使用,但它也可以直接使用 EJS 库渲染模板:
const ejs = require('ejs');
ejs.render('<h1>Hello <%= name %></h1>', { name: 'Sammy' }, (err, html) => {
console.log(html);
});
这种灵活性使得 EJS 可以用于:
- 自定义 Node.js 服务器
- 构建脚本
- 静态站点生成
- 支持模板渲染的其他框架
Express 只是通过 res.render() 方法提供了便捷的集成。
6. EJS 默认是安全的吗?
EJS 通过在使用 <%= %> 标签时转义输出,帮助降低跨站脚本攻击 (XSS) 的风险。转义将特殊字符转换为 HTML 实体,使其无法被浏览器解释为可执行代码。
例如:
<p><%= userInput %></p>
如果 userInput 包含 HTML 或 JavaScript,它会在渲染前被安全转义。
但是,EJS 还提供了 <%- %> 标签,它输出未转义的 HTML:
<%- htmlContent %>
此标签仅应与可信内容一起使用。不转义渲染不可信输入可能会引入 XSS 漏洞。
为了维护安全的应用程序,开发者应该:
- 对大多数模板变量使用
<%= %> - 避免渲染原始用户输入
- 验证和清理输入数据
- 遵循一般的 Web 安全最佳实践
安全性最终取决于模板的使用方式,因此小心处理用户数据至关重要。
结论
在本文中,你学习了如何使用 Express 设置 EJS,使用 res.render() 渲染视图,并使用 partials 和 include() 组织可重用的页面元素。
你还学习了如何从路由传递数据到模板,从而渲染变量和列表,以及在需要平衡灵活性和安全性时如何选择合适的 EJS 输出标签(<%= %> 与 <%- %>)。这将帮助你构建更易维护的 Express 应用,通过保持视图一致性、减少重复的标记,并使在项目增长时更容易添加新页面和功能。
有关更多 Node.js 相关教程,请查看以下文章:
- 如何开始使用 Node.js 和 Express
- Node JS 环境设置 - Node.js 安装
- 如何使用 HTTP 模块在 Node.js 中创建 Web 服务器