JavaScript·

Server-Side Rendering with H3 and EJS

we'll explore how to implement SSR using H3, the lightning-fast HTTP framework from UnJS

Server-side rendering (SSR) remains a crucial technique for building performant web applications.

Today, we'll explore how to implement SSR using H3, the lightning-fast HTTP framework from UnJS, combined with EJS templating. Let's dive into creating a robust templating system that you can use in your next project.

Setting Up H3 with EJS

First, let's create a basic setup that integrates EJS with H3. You'll need to install the necessary dependencies:

npm install h3 ejs

Here's our initial template setup:

import { createApp, createRouter, eventHandler } from 'h3'
import ejs from 'ejs'
import { promises as fs } from 'fs'
import { join } from 'path'

const app = createApp()
const router = createRouter()

// Basic template rendering function
const renderTemplate = async (templatePath, data) => {
  const template = await fs.readFile(templatePath, 'utf-8')
  return ejs.render(template, data)
}

Creating a Template Middleware

The real power comes from creating a reusable middleware for template rendering:

const templateMiddleware = defineEventHandler(async (event) => {
  event.context.render = async (template, data = {}) => {
    const templatePath = join(process.cwd(), 'templates', `${template}.ejs`)
    const content = await fs.readFile(templatePath, 'utf-8')
    
    return ejs.render(content, {
      ...data,
      // Global template helpers
      helpers: {
        formatDate: (date) => new Date(date).toLocaleDateString(),
        capitalize: (str) => str.charAt(0).toUpperCase() + str.slice(1)
      }
    })
  }
})

app.use(templateMiddleware)

Template Structure and Organization

Create a templates directory with this structure:

templates/
  ├── layouts/
  │   └── main.ejs
  ├── partials/
  │   ├── header.ejs
  │   └── footer.ejs
  └── pages/
      ├── home.ejs
      └── about.ejs

Here's an example of a layout file (layouts/main.ejs):

<!DOCTYPE html>
<html>
<head>
    <title><%= title %></title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <%- include('../partials/header') %>
    
    <main>
        <%- content %>
    </main>
    
    <%- include('../partials/footer') %>
</body>
</html>

Implementing Routes with Templates

Now let's set up some routes that use our templates:

router.get('/', eventHandler(async (event) => {
  try {
    const html = await event.context.render('pages/home', {
      title: 'Welcome to H3 with EJS',
      content: await event.context.render('partials/home-content', {
        message: 'Hello from H3!'
      })
    })
    return html
  } catch (error) {
    console.error('Template rendering error:', error)
    return 'Error rendering template'
  }
}))

app.use(router)

Need Help Mastering H3 and Server-Side Rendering?

While this guide covers the basics of integrating EJS with H3, building production-ready applications requires deeper knowledge and experience. I offer specialized mentoring services focused on modern server-side rendering techniques, including:


Copyright © 2024. All rights reserved.