目录

Pug:高性能 JavaScript 模板引擎入门

从 Jade 到 Pug,理解 Node.js 下缩进式模板引擎的设计与用法

Pug 是一款用 JavaScript 实现的高性能模板引擎(template engine),同时支持 Node.js 与浏览器环境,语法深受 Haml 启发。它通过缩进(indentation)而非闭合标签来组织 HTML 结构,让模板代码更简洁、更具可读性。官方仓库 pugjs/pug 的描述是「robust, elegant, feature rich template engine for Node.js」,目前最新稳定版本为 3.0.x,采用 MIT 协议开源。

Pug 的前身叫 Jade。由于 “Jade” 是一个已被注册的商标,项目维护团队在讨论后将其更名为 “Pug”,从 2.0 版本起 pug 成为官方 npm 包名。

如果你的项目仍然依赖 jade 包,不必担心:官方保留了 jade 包名的占用权限,但所有新版本都只会在 pug 名下发布。由于更名恰好与「Jade 2.0.0」的开发同步推进,从 Jade 升级到 Pug 等同于一次主版本号升级流程,语法上有若干修改、弃用和删除,详细差异见官方 Issue #2305

对新手而言,直接从 pug 包和新语法入手即可,无需关心历史包袱。

Pug 提供两种安装方式:作为依赖库引入到 JavaScript 项目,或者作为全局命令行工具使用。

$ npm install pug

在已安装 Node.js 的环境下,可以全局安装 pug-cli

$ npm install pug-cli -g
$ pug --help

命令行模式常用于把 .pug 文件预编译成 JavaScript 函数,便于在浏览器端直接调用:

$ pug --client --no-debug filename.pug

上述命令会生成 filename.js,其中包含已编译的模板函数。

Pug 是一种对空白符敏感(whitespace-sensitive)的语法,用缩进表示嵌套关系,省去了 HTML 的尖括号与闭合标签。

doctype html
html(lang="en")
  head
    title= pageTitle
    script(type='text/javascript').
      if (foo) bar(1 + 5);
  body
    h1 Pug - node template engine
    #container.col
      if youAreUsingPug
        p You are amazing
      else
        p Get on it!
      p.
        Pug is a terse and simple templating language with a
        strong focus on performance and powerful features.

它会被渲染为:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Pug</title>
    <script type="text/javascript">
      if (foo) bar(1 + 5);
    </script>
  </head>
  <body>
    <h1>Pug - node template engine</h1>
    <div id="container" class="col">
      <p>You are amazing</p>
      <p>
        Pug is a terse and simple templating language with a strong focus on
        performance and powerful features.
      </p>
    </div>
  </body>
</html>
  • #container.coldiv#container.col 的简写,即带 id="container"class="col"<div>
  • 属性(attributes)写在括号内,值是合法的 JavaScript 表达式,例如 a(href=url, class='btn')
  • 文本可以用 | 前缀、行内 = 赋值,或紧接在标签后的 . 块文本。
  • //- 是不会输出到 HTML 的注释,// 则会输出到结果中。

Pug 暴露了三个核心方法:compilerenderrenderFile

const pug = require('pug');

// 1. compile:将 Pug 源码编译为可复用的函数
const fn = pug.compile('string of pug', options);
const html = fn(locals);

// 2. render:一次性编译并渲染
const html2 = pug.render('string of pug', { ...options, ...locals });

// 3. renderFile:从文件读取并渲染
const html3 = pug.renderFile('filename.pug', { ...options, ...locals });

常用 Options:

选项含义
filename用于异常信息和 include 解析,使用 include 时必填
compileDebugfalse 时不附加调试信息,体积更小
pretty是否给输出添加缩进美化,默认 false(生产环境建议保持默认)

compile 在内部会把模板编译成 JavaScript 函数,因此首次调用比 render 有些额外开销,但后续调用非常快——适合缓存函数实例复用。

除了基础语法,Pug 还提供了一系列用于模板复用和逻辑组织的特性。

Mixin 类似于可复用的函数,能够接收参数并在模板中反复调用:

mixin pet(name)
  span.pet= name

+pet('cat')
+pet('dog')

include 把另一个 Pug(或纯文本)文件的内容原样插入当前位置,适合拆分头部、尾部等公共片段:

include ./includes/head.pug

通过 extends 继承一个布局模板,再用 block 占位与覆写:

//- layout.pug
html
  head
    block title
  body
    block content

//- page.pug
extends ./layout.pug

block title
  title 首页
block content
  h1 欢迎光临

Pug 支持直接在模板里写 JavaScript:用 - 表示不输出的代码,用 = 表示输出并转义的内容,!= 表示输出但不转义。if/elseeachcase 等控制流语法一应俱全。

Pug 是 Express 默认推荐的服务端模板引擎之一。在 Express 5.x 中启用 Pug 只需两步:

const express = require('express');
const app = express();

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

app.get('/', (req, res) => {
  res.render('index', { title: 'Hello', message: 'Hello from Pug!' });
});

随后将 .pug 模板放在 views/ 目录下即可。Express 会在 res.render 时自动调用 pug.renderFile

Pug 也可以独立运行在浏览器中,官方提供了 standalone 版本。不过由于运行时编译体积较大,文档中明确建议:优先在构建阶段把模板预编译成 JavaScript,再在客户端直接调用编译后的函数。这也是前文 pug --client 命令的核心用途。

Pug 在社区中影响深远,围绕它衍生出丰富的工具链:

  • 编辑器支持:Emacs mode、Vim syntax、TextMate Bundle、VSCode 插件等。
  • 格式化与转换prettier-plugin-pughtml2pug
  • 其他语言移植:PHP、Java、Python、Ruby、C#(ASP.NET Core)等都有语法相近的 Pug 实现。
  • 类似理念引擎:Ruby 的 Haml 与 Slim、Scala 的 Scaml。