Prerendering

Sapling is primarily a server-side rendering framework, but it also supports prerendering routes for static site generation when needed. This guide will explain how prerendering works and when to use it.

Understanding Prerendering

By default, Sapling renders pages on-demand when requests come in. This is fast and efficient for most use cases. However, there are scenarios where you might want to generate static HTML files during build time:

  • Pages with content that rarely changes
  • Improving initial page load for specific routes
  • Reducing server load for high-traffic pages

Basic Usage

Here's a simple example of prerendering a route:

// Define a prerendered route
site.prerender("/about", (c) => {
  return c.html("<h1>About Us</h1>");
});

// Prerender a route with dynamic parameters
site.prerender("/blog/:slug", async (c) => {
  const post = await getPost(c.req.param("slug"));
  return c.html(`<h1>${post.title}</h1>${post.content}`);
}, [
  { slug: "first-post" },
  { slug: "second-post" }
]);

Development vs Production

In development mode (dev: true), prerendered routes behave like normal .get routes for easier development. In production, these routes are generated as static HTML files during the build process.

Build Process

To generate prerendered pages, you'll need to set up a build process. Create a build.ts or build.js file:

// build.ts
import { site } from "./index.ts";

async function build() {
  // Generate prerendered pages in the dist directory
  await site.buildPrerenderRoutes("./dist");
  
  // Run any other build processes
  // await optimizeImages();
  // await generateSearchIndex();
  // await generateSitemap();
  
  console.log("Build completed");
}

build();

Add a build script to your deno.json:

{
  "tasks": {
    "build": "deno run -A build.ts"
  }
}

Or add a build script to your package.json:

"scripts": {
  "build": "node build.js"
}

Serving Prerendered Pages

To serve the prerendered pages, configure your static file serving in your main application:

// index.ts
const site = new Sapling({
  dev: isDev,
  buildDir: "./dist", // Default build directory
});

// Add this as your last route
site.get("/*", serveStatic({
  root: "./dist",
}));

Best Practices

  1. Be Selective: Only prerender routes that truly benefit from it. Most dynamic content is better served through server-side rendering.

  2. Development Experience: Keep in mind that prerendered routes act as normal routes in development, allowing for faster iteration.

  3. Build Performance: Consider the build time impact when prerendering many pages. Each prerendered route adds to your build time.

  4. Data Updates: Remember that prerendered content is static. If your content needs to be frequently updated, server-side rendering might be more appropriate.

Example: Blog with Prerendered Posts

Here's a complete example of prerendering blog posts:

// index.ts
const site = new Sapling({
  dev: isDev,
  buildDir: "./dist",
});

// Get list of blog posts
const posts = [
  { slug: "hello-world", title: "Hello World" },
  { slug: "getting-started", title: "Getting Started" }
];

// Prerender each blog post
site.prerender("/blog/:slug", async (c) => {
  const slug = c.req.param("slug");
  const post = posts.find(p => p.slug === slug);
  
  return c.html(`
    <h1>${post.title}</h1>
    <div>Blog content here...</div>
  `);
}, posts.map(post => ({ slug: post.slug })));

// build.ts
import { site } from "./index.ts";

async function build() {
  await site.buildPrerenderRoutes("./dist");
  console.log("Blog posts prerendered!");
}

When to Use Prerendering

Prerendering is ideal for:

  • High traffic pages that are static and don't change often
  • Documentation pages
  • Marketing pages
  • Blog posts
  • Landing pages

Server-side rendering is better for:

  • User-specific content
  • Frequently updated data
  • Dynamic applications
  • Interactive features

Remember: Sapling's server-side rendering is already optimized for performance. Only reach for prerendering when you have a specific need for static file generation.