Nitro logoNitro

Vite SSR HTML

Server-side rendering with vanilla HTML, Vite, and Nitro.
app/entry-server.ts
import { fetch } from "nitro";

export default {
  async fetch() {
    const quote = (await fetch("/quote").then((res) => res.json())) as {
      text: string;
    };
    return tokenizedStream(quote.text, 50);
  },
};

function tokenizedStream(text: string, delay: number): ReadableStream<Uint8Array> {
  const tokens = text.split(" ");
  return new ReadableStream({
    start(controller) {
      let index = 0;
      function push() {
        if (index < tokens.length) {
          const word = tokens[index++] + (index < tokens.length ? " " : "");
          controller.enqueue(new TextEncoder().encode(word));
          setTimeout(push, delay);
        } else {
          controller.close();
        }
      }
      push();
    },
  });
}

This example renders an HTML template with server-side data and streams the response word by word. It demonstrates how to use Nitro's Vite SSR integration without a framework.

Overview

Add the Nitro Vite plugin to enable SSR

Create an HTML template with a <!--ssr-outlet--> comment where server content goes

Create a server entry that fetches data and returns a stream

Add API routes for server-side data

How It Works

The index.html file contains an <!--ssr-outlet--> comment that marks where server-rendered content will be inserted. Nitro replaces this comment with the output from your server entry.

The server entry exports an object with a fetch method. It calls the /quote API route using Nitro's internal fetch, then returns a ReadableStream that emits the quote text word by word with a 50ms delay between each word.

The quote route fetches a JSON file of quotes from GitHub, caches the result, and returns a random quote. The server entry calls this route to get content for the page.

Learn More