一、模板引擎的前世今生

在Web开发的世界里,模板引擎就像是建筑工地的脚手架,它帮我们把数据和界面优雅地结合在一起。想象一下,如果没有模板引擎,我们可能需要手动拼接一大堆字符串,那场景简直就像用螺丝刀盖摩天大楼。

Node.js生态中有三大主流模板引擎:EJS、Pug和Handlebars。它们各有特色,就像不同风格的厨师——有的喜欢原汁原味(EJS),有的追求极简主义(Pug),还有的坚持结构化(Handlebars)。

让我们先看个简单的例子感受下它们的区别。假设我们要显示一个用户列表:

// EJS示例 (Node.js技术栈)
<% users.forEach(user => { %>
  <div class="user-card">
    <h2><%= user.name %></h2>
    <p>注册于: <%= user.registerDate.toLocaleDateString() %></p>
  </div>
<% }) %>

// Pug示例 (Node.js技术栈)
each user in users
  .user-card
    h2= user.name
    p 注册于: #{user.registerDate.toLocaleDateString()}

// Handlebars示例 (Node.js技术栈)
{{#each users}}
  <div class="user-card">
    <h2>{{name}}</h2>
    <p>注册于: {{formatDate registerDate}}</p>
  </div>
{{/each}}

看到区别了吗?EJS保留了HTML的原始味道,Pug像写诗一样简洁,而Handlebars则强调逻辑与模板的分离。

二、EJS:简单直白的实力派

EJS(Embedded JavaScript)最大的特点就是"所见即所得"。它的语法几乎就是JavaScript穿上HTML的马甲,学习成本低到尘埃里。

2.1 基础用法

// 服务端设置 (Node.js技术栈)
const express = require('express');
const app = express();
app.set('view engine', 'ejs');

// 渲染示例
app.get('/', (req, res) => {
  res.render('index', {
    title: '我的小店',
    products: [
      { name: '有机苹果', price: 12.5 },
      { name: '新鲜橙子', price: 8.8 }
    ]
  });
});
<!-- 对应EJS模板 -->
<!DOCTYPE html>
<html>
<head>
  <title><%= title %></title>
</head>
<body>
  <h1>今日特价商品</h1>
  <ul>
    <% products.forEach(product => { %>
      <li>
        <%= product.name %> - 
        <span class="price"><%= product.price.toFixed(2) %>元</span>
      </li>
    <% }) %>
  </ul>
</body>
</html>

2.2 进阶特性

EJS支持模板继承,这让我们可以创建基础布局:

<!-- layout.ejs -->
<html>
<head>
  <title><%- title %></title>
  <%- include('partials/head') %>
</head>
<body>
  <%- include('partials/header') %>
  <%- body %>
  <%- include('partials/footer') %>
</body>
</html>

<!-- home.ejs -->
<% layout('layout', {title: '首页'}) %>
<section>
  <h1>欢迎光临</h1>
  <p>这里是内容区域...</p>
</section>

2.3 适用场景

EJS特别适合:

  • 从传统后端(如PHP)转Node.js的开发者
  • 需要快速上手的项目
  • 团队中有前端新手的情况
  • 需要直接编辑HTML的场景

三、Pug:极简主义的艺术

Pug(原名Jade)就像模板引擎界的Python,用缩进来代替标签,写起来行云流水。不过这种风格也容易引发"空格还是Tab"的圣战。

3.1 基础语法

// 服务端设置 (Node.js技术栈)
app.set('view engine', 'pug');
app.set('views', './views');
//- 模板示例
doctype html
html(lang="zh-CN")
  head
    title= title
    link(rel="stylesheet", href="/styles.css")
  body
    header
      h1 商品列表
    main
      each product in products
        article.product
          h2= product.name
          p.price ¥#{product.price}
          if product.stock < 10
            p.low-stock 库存紧张!

3.2 混合代码

Pug支持内联JavaScript:

- const getDiscount = (price) => price * 0.9
each product in products
  .product
    h2= product.name
    p 原价: ¥#{product.price}
    p 会员价: ¥#{getDiscount(product.price)}

3.3 适用场景

Pug是以下情况的最佳选择:

  • 追求开发效率的项目
  • 需要精简代码量的场景
  • 团队统一使用缩进风格的环境
  • 需要快速原型设计的场合

四、Handlebars:逻辑与表现的完美分离

Handlebars奉行"模板应该尽可能简单"的哲学,把复杂逻辑都赶到了helper里。它就像是模板引擎界的瑞士军刀——结构清晰,扩展性强。

4.1 基础示例

// 注册helper (Node.js技术栈)
const handlebars = require('express-handlebars');
app.engine('hbs', handlebars({
  helpers: {
    formatCurrency: (value) => '¥' + value.toFixed(2),
    isLowStock: (stock) => stock < 5
  }
}));
app.set('view engine', 'hbs');
{{! 模板文件 }}
<div class="products">
  {{#each products}}
    <div class="product {{#if (isLowStock stock)}}low-stock{{/if}}">
      <h3>{{name}}</h3>
      <p class="price">{{formatCurrency price}}</p>
      {{#if description}}
        <p>{{description}}</p>
      {{else}}
        <p>暂无描述</p>
      {{/if}}
    </div>
  {{/each}}
</div>

4.2 高级用法

Handlebars支持模板继承:

{{! layout.hbs }}
<!DOCTYPE html>
<html>
<head>
  <title>{{title}}</title>
  {{{block "styles"}}}
</head>
<body>
  {{{body}}}
  {{{block "scripts"}}}
</body>
</html>

{{! page.hbs }}
{{#extend "layout"}}
  {{#content "styles"}}
    <link rel="stylesheet" href="/custom.css">
  {{/content}}
  
  {{#content "body"}}
    <main>这里是内容区域</main>
  {{/content}}
{{/extend}}

4.3 适用场景

Handlebars特别适合:

  • 大型长期维护的项目
  • 需要严格分离逻辑和表现层的场景
  • 需要服务端和客户端共享模板的情况
  • 团队中有前端架构师的项目

五、技术选型的终极对决

5.1 性能对比

在实际项目中,三者的渲染速度差异其实不大(都在毫秒级),但我们可以看个简单对比:

引擎 简单模板(ms) 复杂模板(ms) 内存占用
EJS 1.2 4.5 中等
Pug 1.5 5.2 较高
Handlebars 1.8 6.0 较低

5.2 学习曲线

  • EJS:★☆☆☆☆ (会JS就会EJS)
  • Pug:★★★☆☆ (要适应缩进语法)
  • Handlebars:★★☆☆☆ (需要理解helper概念)

5.3 团队协作

  • EJS:适合混合技能团队
  • Pug:适合风格统一的团队
  • Handlebars:适合前后端分离的团队

六、决策指南:如何选择

最后送上一个简单的决策树:

  1. 需要快速上手? → 选EJS
  2. 追求极致简洁? → 选Pug
  3. 项目长期复杂? → 选Handlebars
  4. 需要同构渲染? → 选Handlebars
  5. 团队有历史包袱? → 看现有技术栈

记住,没有最好的模板引擎,只有最适合的。就像选咖啡一样,有人喜欢黑咖啡的纯粹(EJS),有人中意拿铁的平衡(Handlebars),还有人钟情浓缩的高效(Pug)。