freeCodeCamp Advanced Node and Express:Express 应用中配置 Pug 模板引擎的完整实战
本篇技术指南基于 freeCodeCamp 课程仓库中 Advanced Node and Express 认证的首个实战挑战 “Set up a Template Engine”,系统讲解如何在 Express 应用中接入 Pug 模板引擎:包括依赖确认、view engine 与 views 两项关键配置的设定、res.render() 的调用方式,以及课程测试系统对每一步的自动化验证逻辑。读完本文,你将能够独立在一个 Express 应用中完成服务端模板渲染的搭建,并清楚理解每项配置在运行时的实际作用与验收标准。
挑战背景:两种可用的开发方式
该挑战属于 freeCodeCamp Advanced Node and Express 认证(见 区块结构文件),是认证学习路径中的第一个任务。根据 挑战文档 的说明,完成本项目有两种方式:
- 本地开发:克隆课程配套的
boilerplate-advancednode脚手架仓库,在本地环境中完成挑战; - 在线站点构建器:使用任一站点构建平台完成项目,但必须将脚手架仓库中的全部文件纳入项目。
无论选择哪种方式,脚手架已经为你预装了一个关键依赖:
pug@~3.0.0已安装完成,并作为依赖项列在package.json中。
这一点很重要:课程后续的自动化测试会直接检查 package.json 的 dependencies 字段,若你从零搭建项目,务必确保 pug 以近似版本(~3.0.0)锁定并列入依赖。
模板引擎解决了什么问题
文档对模板引擎的定义非常精炼,值得完整理解:
模板引擎让你在应用中可以使用静态模板文件(例如以 Pug 编写的文件)。运行时,模板引擎会把模板文件中的变量替换为服务端提供的实际值,然后把模板转换成一份静态 HTML 文件发送给客户端。这种方式让 HTML 页面的设计更容易,并且无需客户端发起 API 调用就能在页面上展示变量。
从这段话可以拆解出三个技术要点:
- 静态模板 + 运行时渲染:模板文件(如
.pug)本身不是最终产物,服务端在请求到来时执行渲染,输出的才是浏览器收到的静态 HTML。 - 变量由服务端注入:页面上展示的数据直接来自服务器内存或数据库,渲染完成后以 HTML 形式下发。
- 省去一次客户端 API 往返:与纯前端方案相比,初始页面数据不需要等 HTML 加载完后再由 JS 发起 API 请求拉取,首屏呈现更直接。
Pug 本身是一种高度依赖空白与缩进来表示嵌套、语法极简的模板语言。课程下一个挑战 Use a Template Engine's Powers 中给出的示例可以直观感受其风格:
head
script(type='text/javascript').
if (foo) bar(1 + 5);
body
if youAreUsingPug
p You are amazing
else
p Get on it!
上述 Pug 代码渲染后产出对应的 <head>/<body> 标准 HTML 结构。掌握这一点对理解本挑战“页面由空白变为渲染成功”的验收标准很有帮助。
第一步:用 set 方法指定 view engine
Express 默认并不知道你要用哪一种模板引擎,因此必须显式告知它。使用 Express 应用实例的 set 方法,将 view engine 属性赋值为 pug:
app.set('view engine', 'pug');
这行配置会写入 Express 内部的 app.settings 对象。课程测试正是利用这一点来验证的(详见下文“验收标准”一节):测试会读取应用设置并断言 settings['view engine'] 严格等于字符串 "pug"。注意这里是精确匹配,写成 "Pug" 或其他变体都会失败。
第二步:把 views 指向 ./views/pug 目录
指定引擎之后,还要告诉 Express 去哪里找模板文件。再加一个 set 调用,把 views 属性指向 ./views/pug 目录:
app.set('views', './views/pug');
该配置的含义是:Express 渲染所有视图时都以此为基准目录。也就是说,之后凡是 res.render('index'),Express 实际查找的就是 ./views/pug/index.pug。脚手架的 index.pug 模板就放在该目录下,保持相对路径 ./views/pug 原样(含 ./ 前缀)是关键——课程的自动化测试对此做的是字符串精确比对,而不是路径解析后的等价性判断。
第三步:在首页路由中调用 res.render('index')
配置完成后,在首页路由(/)的处理器中调用 res.render(),并将 index 作为第一个参数传入:
app.get('/', function (req, res) {
res.render('index');
});
res.render('index') 会触发对 ./views/pug/index.pug 的渲染流程:Pug 编译模板 → 生成静态 HTML → 作为响应体发送。如果一切按计划执行,应用首页将不再是空白页,而是显示一条渲染成功的提示信息(该页面 HTML 中包含 “FCC Advanced Node and Express” 字样与 pug-success-message 标识,二者都是课程测试的断言锚点,见下文)。
验收标准:课程测试如何逐步验证你的实现
本挑战的 # --hints-- 部分定义了 5 组自动化断言,它们以 HTTP 请求的形式作用于你部署/运行中的应用(相关测试端点如 /_api/package.json、/_api/app 是课程测试平台暴露的自省接口)。这些断言也构成了本任务事实上的“验收清单”:
- Pug 必须是依赖项
const url = new URL("/_api/package.json", code);
const res = await fetch(url);
const packJson = await res.json();
assert.property(
packJson.dependencies,
'pug',
'Your project should list "pug" as a dependency'
);
检查 package.json 的 dependencies 中是否存在 pug 键。
- View engine 必须为 Pug
const url = new URL("/_api/app", code);
const res = await fetch(url);
const app = await res.json();
assert.equal(app?.settings?.['view engine'], "pug");
通过 /_api/app 端点读取应用设置,断言 view engine 精确等于 "pug"。
views属性必须为./views/pug
assert.equal(app?.settings?.views, "./views/pug");
注意这里比对的是字面字符串 "./views/pug",因此路径写法必须与课程要求完全一致。
- 首页必须渲染出成功提示
const url = new URL("/", code);
const res = await fetch(url);
const data = await res.text();
assert.match(
data,
/FCC Advanced Node and Express/gi,
'You successfully rendered the Pug template!'
);
请求根路径 /,断言返回的 HTML 文本匹配 FCC Advanced Node and Express(忽略大小写)。
- Pug 必须真正在工作
assert.match(
data,
/pug-success-message/gi,
'Your projects home page should now be rendered by pug with the projects .pug file unaltered'
);
断言页面包含 pug-success-message 标识,且错误提示明确要求 .pug 文件未被修改——即你不能通过改写模板文件来“绕过”渲染,必须让 Express 真正走 Pug 渲染管线产出页面。
在认证体系中的位置与后续路线
从 区块结构文件 定义的 challengeOrder 可以看出,本挑战是整个 Advanced Node and Express 认证的起点,模板引擎的设置是后续所有功能的地基:
- 紧接其后的 Use a Template Engine's Powers 会教你在
res.render中传入第二个参数(变量对象),把服务端变量注入模板,例如res.render('index', { title: 'Hello', message: 'Please log in' }),模板内可用#{variable}或p=variable语法消费; - 再往后是 Set up Passport,引入
express-session与 Passport 完成会话与认证体系; - 认证后段还包括 Socket.IO 实时通信等一系列挑战。
模板渲染之所以被安排在最前面,正是因为 Passport 登录状态展示、用户信息等后续功能都需要把服务端数据渲染进 HTML 页面——view engine 与 views 两项配置正是这一切渲染能力的前提。
小结
本挑战的核心操作只有三步,却覆盖了 Express 模板渲染的全部关键链路:
| 步骤 | 配置/代码 | 运行时作用 |
|---|---|---|
| 1 | app.set('view engine', 'pug') |
告知 Express 使用 Pug 渲染引擎 |
| 2 | app.set('views', './views/pug') |
指定模板基准目录 |
| 3 | res.render('index')(首页路由) |
渲染 ./views/pug/index.pug 并下发 HTML |
配合 package.json 中已就绪的 pug@~3.0.0 依赖,即可让 Express 应用具备“服务端渲染 + 静态 HTML 下发”的完整能力。实现时请保持 .pug 模板文件原样不动,并以页面成功渲染出包含 “FCC Advanced Node and Express” 与 pug-success-message 标识的 HTML 作为自检标准——这也正是课程自动化测试的五项断言所验证的内容。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00