阿里云主机折上折
  • 微信号
Current Site:Index > The template engine translates this sentence into English.

The template engine translates this sentence into English.

Author:Chuan Chen 阅读数:62595人阅读 分类: Node.js

Basic Concepts of Template Engines

A template engine is a tool that combines data with templates to generate final output. It allows developers to embed dynamic content into static templates by using specific syntax markers for dynamic parts, which are replaced with actual data at runtime. In the Node.js environment, there are various template engines to choose from, each with its unique syntax and features.

// A simple template example
const template = "Hello, <%= name %>!";
const data = { name: "World" };
// After processing by the template engine, the output is: "Hello, World!"

Mainstream Node.js Template Engines

EJS (Embedded JavaScript)

EJS is a simple templating language that embeds JavaScript syntax into HTML. Its syntax is close to native JavaScript, making it easy to learn.

// EJS template example
<ul>
  <% users.forEach(function(user){ %>
    <li><%= user.name %></li>
  <% }); %>
</ul>

EJS supports the following main syntax:

  • <% %> Executes JavaScript code but does not output
  • <%= %> Outputs escaped values
  • <%- %> Outputs raw HTML (unescaped)

Pug (formerly Jade)

Pug uses an indentation-based syntax, reducing redundant characters in templates and making the code more concise.

// Pug template example
ul
  each user in users
    li= user.name

Pug features include:

  • Indentation-based hierarchical structure
  • Support for mixins and inheritance
  • Auto-closing tags
  • Rich filter system

Handlebars

Handlebars is a logic-less templating engine that emphasizes the separation of templates and business logic.

<!-- Handlebars template example -->
<ul>
  {{#each users}}
    <li>{{name}}</li>
  {{/each}}
</ul>

Handlebars core features:

  • {{expression}} Outputs expressions
  • {{#helper}} Block helpers
  • {{> partial}} Includes partial templates
  • Supports custom helper functions

How Template Engines Work

Template engines typically go through the following processing stages:

  1. Parsing Phase: Converts the template string into an Abstract Syntax Tree (AST)
  2. Compilation Phase: Transforms the AST into executable JavaScript functions
  3. Execution Phase: Calls the generated functions with input data to produce the final output
// Simplified implementation of a template engine
function compile(template) {
  const tokens = template.split(/(<%=\s*[\w\.]+\s*%>)/);
  let code = 'let output = "";\n';
  
  tokens.forEach(token => {
    if (token.match(/^<%=\s*([\w\.]+)\s*%>$/)) {
      const variable = token.match(/<%=\s*([\w\.]+)\s*%>/)[1];
      code += `output += ${variable};\n`;
    } else {
      code += `output += ${JSON.stringify(token)};\n`;
    }
  });
  
  code += 'return output;';
  return new Function('data', code);
}

Advanced Template Features

Template Inheritance and Inclusion

Modern template engines often support inheritance mechanisms, allowing the creation of base templates and extended templates.

// Template inheritance in Pug
// base.pug
html
  head
    block title
      title Default Title
  body
    block content

// home.pug
extends base.pug

block title
  title Home Page

block content
  h1 Welcome to the Home Page

Custom Filters

Some template engines allow defining custom filters to process output content.

// EJS custom filter example
const ejs = require('ejs');
ejs.filters.uppercase = function(str) {
  return str.toUpperCase();
};

// Usage in templates
// <%= name | uppercase %>

Conditional Rendering and Loops

Template engines provide conditional statements and loop structures to handle complex data display logic.

<!-- Handlebars conditionals and loops -->
{{#if isAdmin}}
  <button class="admin">Admin Panel</button>
{{else}}
  <button class="user">User Panel</button>
{{/if}}

<ul>
  {{#each items}}
    <li class="{{#if @first}}first{{/if}} {{#if @last}}last{{/if}}">
      {{@index}}: {{this}}
    </li>
  {{/each}}
</ul>

Performance Optimization Techniques

Precompiling Templates

Most template engines support precompiling templates to improve runtime performance.

// EJS precompilation example
const ejs = require('ejs');
const template = ejs.compile('<%= message %>', {client: true});

// The compiled template can be reused multiple times
console.log(template({message: 'Hello'}));

Caching Mechanisms

Proper use of template caching can significantly improve application performance.

// Using EJS caching in Express
app.set('view cache', true);
app.set('view engine', 'ejs');

Partial Rendering

Only update the parts of the template that need to change, rather than the entire template.

// Implementing partial template updates
function updatePartial(templateId, data) {
  const template = document.getElementById(templateId).innerHTML;
  const rendered = ejs.render(template, data);
  document.getElementById('target').innerHTML = rendered;
}

Security Considerations

XSS Protection

Template engines typically provide automatic escaping to prevent XSS attacks.

// Automatic escaping in EJS
// <%= userInput %> Automatically escapes HTML
// <%- userInput %> Outputs raw HTML—use with caution

Template Injection Protection

Avoid using user input directly as template content.

// Unsafe practice
const userTemplate = req.query.template;
ejs.render(userTemplate, data); // May lead to template injection

// Safe practice
const safeTemplates = {
  'template1': '<%= safeData %>',
  'template2': '<%- trustedData %>'
};
ejs.render(safeTemplates[req.query.template], data);

Integration with Other Technologies

Integration with Express Framework

Most template engines offer seamless integration with Express.

// Configuring EJS in Express
const express = require('express');
const app = express();

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

app.get('/', (req, res) => {
  res.render('index', { title: 'Home Page' });
});

Combining with Frontend Frameworks

Template engines can also be used on the frontend, alongside modern frontend frameworks.

// Using EJS in React
function renderEjsInReact(template, data) {
  const html = ejs.render(template, data);
  return <div dangerouslySetInnerHTML={{__html: html}} />;
}

Static Site Generation

Template engines are commonly used in static site generators.

// Generating static pages with a template engine
const fs = require('fs');
const template = fs.readFileSync('template.ejs', 'utf8');
const html = ejs.render(template, {pageTitle: 'About Us'});
fs.writeFileSync('about.html', html);

Practical Use Cases

Dynamic Email Templates

// Generating email content
const emailTemplate = `
  <h1>Hello <%= user.name %>,</h1>
  <p>Your order #<%= order.id %> has been shipped.</p>
  <p>Tracking number: <%= order.trackingNumber %></p>
`;

const emailContent = ejs.render(emailTemplate, {
  user: {name: 'John Doe'},
  order: {id: '12345', trackingNumber: 'ZYX987'}
});

Multilingual Support

// Handling multilingual templates
const locales = {
  en: {
    welcome: 'Welcome, <%= name %>!',
    products: 'Our Products'
  },
  es: {
    welcome: '¡Bienvenido, <%= name %>!',
    products: 'Nuestros Productos'
  }
};

function renderLocalized(templateKey, lang, data) {
  return ejs.render(locales[lang][templateKey], data);
}

Dynamic Configuration File Generation

// Generating configuration files
const configTemplate = `
  server {
    listen <%= port %>;
    server_name <%= domain %>;
    
    location / {
      root <%= root %>;
      index index.html;
    }
  }
`;

const nginxConfig = ejs.render(configTemplate, {
  port: 8080,
  domain: 'example.com',
  root: '/var/www/html'
});

Developing Custom Template Engines

Creating a simple template engine can help deepen understanding of how they work.

class SimpleTemplateEngine {
  constructor(delimiters = ['{{', '}}']) {
    this.delimiters = delimiters;
  }

  compile(template) {
    const [open, close] = this.delimiters;
    const pattern = new RegExp(`${open}\\s*(.+?)\\s*${close}`, 'g');
    
    const code = [
      'let output = [];',
      `with(data) {`,
      `  output.push(\`${template.replace(pattern, '\');\n  output.push($1);\n  output.push(`')}\`);`,
      `}`,
      `return output.join('');`
    ].join('\n');
    
    return new Function('data', code);
  }

  render(template, data) {
    const compiled = this.compile(template);
    return compiled(data);
  }
}

// Usage example
const engine = new SimpleTemplateEngine();
const result = engine.render('Hello {{name}}!', {name: 'World'});
console.log(result); // Output: Hello World!

Debugging Techniques for Template Engines

Error Tracing

// Enabling debugging in EJS
ejs.renderFile('template.ejs', data, {
  debug: true,
  compileDebug: true
}, (err, html) => {
  if (err) {
    console.error('Template error:', err);
    return;
  }
  console.log(html);
});

Context Inspection

// Inspecting available data in templates
/*
<% console.log('Template data:', Object.keys(data)); %>
<% if (!data.user) { %>
  <p>Warning: user data is missing</p>
<% } %>
*/

Performance Profiling

// Measuring template rendering time
console.time('template-render');
ejs.render(template, largeData);
console.timeEnd('template-render');

Future Trends

Template Engines and Web Components

// Defining Web Components with template engines
class MyElement extends HTMLElement {
  constructor() {
    super();
    const template = `
      <style>
        :host {
          display: block;
        }
      </style>
      <div class="container">
        <slot></slot>
      </div>
    `;
    this.attachShadow({mode: 'open'}).innerHTML = template;
  }
}

customElements.define('my-element', MyElement);

Applications in Server-Side Rendering (SSR)

// Using EJS in Next.js
import ejs from 'ejs';
import fs from 'fs';
import path from 'path';

export async function getServerSideProps() {
  const templatePath = path.join(process.cwd(), 'templates', 'page.ejs');
  const template = fs.readFileSync(templatePath, 'utf8');
  const html = ejs.render(template, { title: 'SSR Page' });
  
  return {
    props: { html },
  };
}

function Page({ html }) {
  return <div dangerouslySetInnerHTML={{ __html: html }} />;
}

Static Type Checking Integration

// Defining TypeScript interfaces for template data
interface TemplateData {
  title: string;
  items: Array<{
    id: number;
    name: string;
    price: number;
  }>;
  showPrice: boolean;
}

function renderTemplate(data: TemplateData): string {
  return ejs.render(templateString, data);
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:ORM工具使用

下一篇:构建工具

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.