Coding, Insights, and Digital Discoveries ๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป

From Stay-at-Home Mom to a Developer After 50

Published on

Compare CSR, SSR, SSG, and ISR: Lessons Learned While Building the Sitemap Page

CSR vs. SSR vs. SSG website performance

As 2024 came to a close, I took some time during the holiday season to reflect, recharge, and reimagine my blog. Iโ€™m thrilled to share one of the exciting new additions Iโ€™ve been working onโ€”a Sitemap Page! ๐ŸŒ This sitemap page isnโ€™t for search engines to crawl, but solely for you, my readers, to easily navigate my blog. Itโ€™s a single page where every blog post title is displayed in chronological order, making it easier than ever for readers to explore, revisit, or catch up on content that might have been missed.

Working on the new sitemap page wasnโ€™t just about organizing contentโ€”it was also an opportunity to deepen my understanding of some crucial web development concepts:

  • Client-Side Rendering (CSR),
  • Server-Side Rendering (SSR),
  • Static Site Generation (SSG),
  • and Incremental Static Regeneration (ISR).

These concepts are at the heart of modern web development, especially when using frameworks like Next.js, and they play a significant role in website performance, user experience, and SEO. Letโ€™s break them down in a way thatโ€™s easy to understand, even if youโ€™re just starting out with Next.js! ๐Ÿ˜Š

Client-Side Rendering (CSR) for the Sitemap Page ๐Ÿ–ฅ๏ธ

In Client-Side Rendering (CSR), the browser downloads a minimal HTML page and then uses JavaScript to fetch data and render the content dynamically. Think of it like ordering a pizza ๐Ÿ•: you place the order (fetch the data), wait for it to arrive (load the content), and then enjoy it (see the page).

Letโ€™s take my sitemap page as an example. The sitemap page lists all blog post titles, grouped by month in descending order, with each title linking to its respective post page.

Step 1: Fetching Data on the Client Side ๐Ÿ“ฅ

In CSR, JavaScript (typically with fetch or axios) is used to retrieve the data from an API or a local JSON file. Hereโ€™s how you might fetch the data in a Next.js component (without using Contentlayer2):

import { useEffect, useState } from 'react';

const SitemapPage = () => {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    // Fetch data from your API or local file
    fetch('/api/posts')
      .then((response) => response.json())
      .then((data) => {
        // Sort posts by date in descending order
        const sortedPosts = data.sort((a, b) => new Date(b.date) - new Date(a.date));
        setPosts(sortedPosts);
      })
      .catch((error) => console.error('Error fetching posts:', error));
  }, []);

  // Group posts by month
  const groupedPosts = posts.reduce((acc, post) => {
    const month = new Date(post.date).toLocaleString('default', { month: 'long', year: 'numeric' });
    if (!acc[month]) {
      acc[month] = [];
    }
    acc[month].push(post);
    return acc;
  }, {});

  return (
    <div>
      <h1>Sitemap</h1>
      {Object.entries(groupedPosts).map(([month, posts]) => (
        <div key={month}>
          <h2>{month}</h2>
          <ul>
            {posts.map((post) => (
              <li key={post.slug}>
                <a href={`/posts/${post.slug}`}>{post.title}</a>
              </li>
            ))}
          </ul>
        </div>
      ))}
    </div>
  );
};

export default SitemapPage;

Step 2: Displaying the Data ๐Ÿ–ผ๏ธ

Once the data is fetched, itโ€™s stored in the componentโ€™s state (posts). The component then groups the posts by month and renders them in a list. Each post title is a link to the corresponding post page.

Understanding CSR: Pros and Cons โš–๏ธ

Pros:

  • Dynamic and Interactive: CSR allows for a smooth, app-like experience. ๐Ÿš€
  • Fast Initial Load: The initial HTML page is lightweight. โšก

Cons:

  • Slower Time to Interactive: Users might have to wait for the data to load. โณ
  • SEO Challenges: Search engines may not wait for JavaScript to execute, which can hurt your rankings. ๐Ÿ“‰

Why SSR or SSG Might Be Better for Performance ๐Ÿš€

While CSR is great for dynamic, interactive apps, itโ€™s not always the best choice for performance. Letโ€™s explore why Server-Side Rendering (SSR) and Static Site Generation (SSG) are often better options:

Server-Side Rendering (SSR) ๐Ÿ–ฅ๏ธ

With SSR, the server fetches the data and renders the HTML on each request before sending it to the client. Think of it like a chef ๐Ÿง‘โ€๐Ÿณ preparing your meal in the kitchen and serving it ready-to-eat.

TIP

  • Faster Time to First Byte (TTFB): Users see content almost immediately. โฑ๏ธ
  • Better SEO: Search engines receive the complete HTML, making indexing easier. ๐Ÿ“ˆ
  • Ideal for Dynamic Content: Perfect for pages with frequently changing data, like news or sports scores. ๐Ÿˆ

Static Site Generation (SSG) ๐Ÿ“„

SSG generates the HTML at build time and reuses it for each request. Imagine a vending machine ๐Ÿฅค: the snacks are already prepared and ready to grab. This is exactly what Contentlayer2 does for blogging websites.

TIP

  • Extremely Fast Load Times: Pre-rendered HTML can be served directly from a CDN. โšก
  • Excellent SEO: Content is immediately available for search engines. ๐Ÿ“Š
  • Ideal for Static Content: Best for pages that donโ€™t change often, like a blog sitemap. ๐Ÿ“š

Key Differences When Loading the Sitemap Page ๐Ÿ”

  • CSR: The browser fetches and renders the data, which can be slow. ๐Ÿข
  • SSR: The server handles everything, providing faster load times. ๐Ÿš€
  • SSG: The page is pre-rendered at build time, offering the fastest performance. โšก

Choosing the Right Approach for My Sitemap Page ๐ŸŽฏ

For my blog, I use Contentlayer2 for content management. It generates a local file (allBlogs) at build time, which includes all the blog post metadata (titles, slugs, dates). Since the Next.js App Router defaults to SSG, the sitemap page is automatically pre-rendered. This is perfect because the list of articles doesnโ€™t change frequently. ๐Ÿ†


import { allBlogs } from "contentlayer/generated";
import Link from "next/link";
import { Metadata } from "next";

export const metadata: Metadata = {
  title: "Site Map",
  description: "Browse articles organized by month.",
};

export default function SitemapPage() {
  const articlesByMonth = allBlogs
    .filter((post) => !post.draft)
    .reduce((acc, post) => {
      const date = new Date(post.date);
      const month = date.toLocaleString("default", { month: "long" });
      const year = date.getFullYear();
      const key = `${month} ${year}`;
      if (!acc[key]) acc[key] = [];
      acc[key].push(post);
      return acc;
    }, {} as Record<string, typeof allBlogs>);

  const sortedMonths = Object.keys(articlesByMonth).sort((a, b) => {
    const [monthA, yearA] = a.split(" ");
    const [monthB, yearB] = b.split(" ");
    const dateA = new Date(`${monthA} 1, ${yearA}`);
    const dateB = new Date(`${monthB} 1, ${yearB}`);
    return dateB.getTime() - dateA.getTime();
  });

  return (
    <div className="p-8">
      <h1 className="text-2xl font-bold mb-4">Site Map</h1>
      {sortedMonths.map((month) => (
        <div key={month} className="mb-6">
          <h2 className="text-xl font-semibold">{month}</h2>
          <ul className="list-disc ml-6">
            {articlesByMonth[month].map((post) => (
              <li key={post._id}>
                <Link
                  href={`/${post.path}`}
                  className="text-gray-600 hover:underline"
                >
                  {post.title}
                </Link>
              </li>
            ))}
          </ul>
        </div>
      ))}
    </div>
  );
}

When to Use SSR vs. SSG ๐Ÿค”

Use SSR When:

  • You need real-time updates, like news or stock prices. ๐Ÿ“ˆ
  • The content is personalized, like user dashboards. ๐Ÿ› ๏ธ
  • The data changes frequently, like sports scores. ๐Ÿ€

Use SSG When:

  • The content is static, like a blog or documentation. ๐Ÿ“š
  • The data doesnโ€™t change often, like a portfolio or marketing site. ๐ŸŽจ
  • You want blazing-fast performance and great SEO. โšก๐Ÿ“Š

Bonus: Combining SSR and SSG ๐ŸŽจ

Sometimes, the best approach is a mix of SSR and SSG. For example:

  • Use SSG for static content and fetch dynamic data client-side. ๐Ÿ–ผ๏ธ
  • Use Incremental Static Regeneration (ISR) to update specific pages periodically. ๐Ÿ”„
  • Use SSR for dynamic pages and SSG for static pages. ๐Ÿ› ๏ธ๐Ÿ“„

This hybrid approach ensures optimal performance, scalability, and flexibility for all kinds of websites. ๐ŸŒŸ

Appreciating Contentlayer2โ€™s Brilliance ๐Ÿ› ๏ธ

After diving deep into the comparison of CSR, SSR, and SSG, I gained a newfound appreciation for how Contentlayer2 is structured and its incredible functionality. ๐Ÿš€ Contentlayer2 works behind the scenes to generate blog posts at build time, seamlessly converting markdown content into HTML. This process ensures that my blog is not only fast and efficient but also optimized for SEO. ๐ŸŒŸ


Building the sitemap page was more than just a technical taskโ€”it was a journey of discovery. I learned the strengths and weaknesses of CSR, SSR, and SSG, and how to choose the right approach for different use cases. But most importantly, I gained a deeper understanding of how Contentlayer2 powers my blog, making it fast, efficient, and optimized for search engines. ๐Ÿš€

Thank you for joining me on this journey, and I hope this article helps you make informed decisions about rendering strategies in your Next.js projects. Happy coding, and see you in the next post! ๐Ÿ˜Š๐Ÿ‘‹

โ† See All Posts