CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-pug

A clean, whitespace-sensitive template language for writing HTML

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

express-integration.mddocs/

Express.js Integration

Native Express.js view engine support for seamless web application integration. Pug provides a built-in Express view engine that handles template rendering within the Express middleware pipeline.

Capabilities

Express View Engine Function

The __express function provides Express.js view engine interface compatibility.

/**
 * Express.js view engine interface
 * @param path - Template file path
 * @param options - View options from Express including locals
 * @param fn - Express callback function
 */
function __express(path, options, fn);

Usage Examples:

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

const app = express();

// Set Pug as the view engine
app.set('view engine', 'pug');
app.set('views', './views');

// Express routes using Pug templates
app.get('/', (req, res) => {
  res.render('index', {
    title: 'Home Page',
    message: 'Welcome to our site!'
  });
});

app.get('/user/:id', (req, res) => {
  const user = getUserById(req.params.id);
  res.render('user-profile', {
    user: user,
    isOwner: req.user && req.user.id === user.id
  });
});

app.listen(3000);

Express Configuration

Basic Setup:

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

// Configure Pug as view engine
app.set('view engine', 'pug');
app.set('views', path.join(__dirname, 'views'));

// Optional: Configure Pug-specific settings
app.locals.pretty = true; // Pretty-print HTML (development only)
app.locals.cache = process.env.NODE_ENV === 'production';

Advanced Configuration:

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

const app = express();

// Custom Pug configuration
app.engine('pug', (filePath, options, callback) => {
  // Custom options for all Pug templates
  const pugOptions = {
    ...options,
    basedir: app.get('views'),
    cache: app.get('env') === 'production',
    compileDebug: app.get('env') !== 'production',
    filters: {
      markdown: (text) => require('markdown-it')().render(text),
      currency: (amount) => '$' + parseFloat(amount).toFixed(2)
    }
  };
  
  return pug.renderFile(filePath, pugOptions, callback);
});

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

Template Directory Structure

Typical Express + Pug project structure:

project/
├── views/
│   ├── layout.pug          # Base layout template
│   ├── index.pug           # Home page
│   ├── error.pug           # Error page
│   ├── partials/
│   │   ├── header.pug      # Header component
│   │   ├── footer.pug      # Footer component
│   │   └── nav.pug         # Navigation
│   └── users/
│       ├── profile.pug     # User profile
│       └── settings.pug    # User settings
├── public/                 # Static assets
├── routes/                 # Express routes
└── app.js                 # Main application

Template Inheritance with Express

Layout Template (views/layout.pug):

doctype html
html
  head
    title= title || 'My App'
    link(rel='stylesheet', href='/css/style.css')
    block head
  body
    include partials/header
    main.container
      block content
    include partials/footer
    script(src='/js/app.js')
    block scripts

Page Template (views/index.pug):

extends layout

block head
  meta(name='description', content='Welcome to our homepage')

block content
  h1= title
  p= message
  
  if user
    p Welcome back, #{user.name}!
  else
    a(href='/login') Please log in

block scripts
  script(src='/js/homepage.js')

Express Middleware Integration

Template Variables Middleware:

// Add common variables to all templates
app.use((req, res, next) => {
  res.locals.currentUser = req.user;
  res.locals.currentPath = req.path;
  res.locals.environment = app.get('env');
  res.locals.moment = require('moment'); // Date utility
  next();
});

// Now available in all templates
app.get('/dashboard', (req, res) => {
  res.render('dashboard', {
    title: 'Dashboard'
    // currentUser, currentPath, environment, moment are automatically available
  });
});

Error Handling Middleware:

// Custom error page rendering
app.use((err, req, res, next) => {
  res.status(err.status || 500);
  
  if (req.accepts('html')) {
    res.render('error', {
      title: 'Error',
      error: app.get('env') === 'development' ? err : {},
      message: err.message,
      status: err.status || 500
    });
  } else if (req.accepts('json')) {
    res.json({ error: err.message });
  } else {
    res.type('txt').send(err.message);
  }
});

Advanced Express Features

Conditional Rendering:

app.get('/products', (req, res) => {
  const products = getProducts();
  const viewMode = req.query.view || 'grid';
  
  res.render('products', {
    title: 'Products',
    products: products,
    viewMode: viewMode,
    showFilters: products.length > 10,
    isAdmin: req.user && req.user.role === 'admin'
  });
});

Template Caching Strategy:

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

// Environment-based caching
if (app.get('env') === 'production') {
  app.enable('view cache'); // Enable Express view caching
  app.locals.cache = true;  // Enable Pug template caching
  app.locals.compileDebug = false;
} else {
  app.locals.pretty = true; // Pretty HTML in development
  app.locals.compileDebug = true;
}

Custom Helper Functions:

// Add helper functions to templates
app.locals.formatDate = (date) => {
  return new Date(date).toLocaleDateString();
};

app.locals.truncate = (text, length = 100) => {
  return text.length > length ? text.substring(0, length) + '...' : text;
};

app.locals.asset = (path) => {
  // Asset versioning helper
  const version = app.get('env') === 'production' ? '?v=1.0.0' : '';
  return path + version;
};

// Usage in templates:
// p= formatDate(post.createdAt)
// p= truncate(post.content, 150)
// link(rel='stylesheet', href=asset('/css/style.css'))

Performance Optimization

Production Configuration:

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

if (process.env.NODE_ENV === 'production') {
  // Enable all Express optimizations
  app.enable('view cache');
  app.set('trust proxy', 1);
  
  // Pug optimizations
  app.locals.cache = true;
  app.locals.compileDebug = false;
  app.locals.pretty = false;
  
  // Precompile critical templates
  const criticalTemplates = ['layout', 'index', 'error'];
  criticalTemplates.forEach(template => {
    pug.compileFile(`./views/${template}.pug`, { cache: true });
  });
}

Memory Management:

// Monitor template cache size in production
if (process.env.NODE_ENV === 'production') {
  setInterval(() => {
    const cacheSize = Object.keys(pug.cache).length;
    console.log(`Template cache size: ${cacheSize}`);
    
    if (cacheSize > 100) {
      console.warn('Template cache is large, consider cleanup');
    }
  }, 300000); // Check every 5 minutes
}

Error Handling

Template Rendering Errors:

app.get('/user/:id', (req, res, next) => {
  try {
    const user = getUserById(req.params.id);
    
    if (!user) {
      return res.status(404).render('404', {
        title: 'User Not Found',
        message: 'The requested user could not be found.'
      });
    }
    
    res.render('user-profile', { user });
  } catch (err) {
    // Template rendering error
    console.error('Template error:', err);
    next(err);
  }
});

Development Error Pages:

if (app.get('env') === 'development') {
  app.use((err, req, res, next) => {
    res.status(err.status || 500);
    res.render('error', {
      title: 'Development Error',
      message: err.message,
      error: err, // Full error object in development
      stack: err.stack
    });
  });
}

Testing Templates with Express

Template Testing Setup:

const request = require('supertest');
const express = require('express');

const app = express();
app.set('view engine', 'pug');
app.set('views', './test/fixtures/views');

app.get('/test', (req, res) => {
  res.render('test-template', { message: 'Hello Test' });
});

// Test template rendering
describe('Template Rendering', () => {
  it('should render test template', (done) => {
    request(app)
      .get('/test')
      .expect(200)
      .expect(/<p>Hello Test<\/p>/)
      .end(done);
  });
});

Mocking Template Data:

const mockData = {
  users: [
    { id: 1, name: 'Alice', email: 'alice@example.com' },
    { id: 2, name: 'Bob', email: 'bob@example.com' }
  ]
};

app.get('/test-users', (req, res) => {
  res.render('users', {
    title: 'Test Users',
    users: mockData.users
  });
});

This completes the Express.js integration documentation, providing comprehensive coverage of how to use Pug as an Express view engine with practical examples and best practices.

Install with Tessl CLI

npx tessl i tessl/npm-pug

docs

client-compilation.md

compilation.md

configuration.md

express-integration.md

index.md

rendering.md

tile.json