Skip to content

Add SSR for Public Notes (SEO + Performance) #47

@typelets

Description

@typelets

Problem

Public notes pages (/p/:slug) are client-side rendered (CSR). This means:

  • Google sees empty HTML - Only <div id="root"></div> until JavaScript runs
  • Poor SEO - Content isn't indexed properly
  • No social previews - Twitter/Facebook/LinkedIn can't read meta tags
  • Slower perceived load - Users see loading state before content

Solution

Add Server-Side Rendering (SSR) for public notes using Cloudflare Workers.

Architecture

Request: /p/my-note
        │
        ▼
┌─────────────────────┐
│  Cloudflare Cache   │──── HIT ────▶ Return cached HTML
└──────────┬──────────┘
           │ MISS
           ▼
┌─────────────────────┐
│  Cloudflare Worker  │
│  (SSR Logic)        │
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│  Fetch note from    │
│  PostgreSQL           │
└──────────┬──────────┘
           │
           ▼
Generate full HTML ──▶ Cache it ──▶ Return to user

How It Works

  1. Worker intercepts /p/* routes

  2. Check Cloudflare cache - Return immediately if cached

  3. On cache miss:

    • Fetch note from PostgreSQL (public notes endpoint)
    • Generate complete HTML with:
      • Note title in <title>
      • Full meta tags (description, OG image, author)
      • Actual note content in body
      • Theme/styling
    • Cache the response
    • Return to user
  4. React hydration - After HTML loads, React attaches event listeners for interactivity (theme toggle, TOC, etc.)

Benefits

Before (CSR) After (SSR)
Empty HTML for crawlers Full content for Google
No social previews Rich previews on Twitter/LinkedIn
Loading spinner first Content visible immediately
API call on every visit Cached HTML responses

Implementation Steps

  • Create Cloudflare Worker for /p/* routes
  • Add PostgreSQL client to Worker
  • Create HTML template matching current PublicNotePage design
  • Implement note fetching and HTML generation
  • Add proper cache headers (s-maxage for edge caching)
  • Set up cache purging when notes are updated
  • Add fallback to SPA if Worker fails
  • Test with Google Search Console
  • Test social previews (Twitter Card Validator, Facebook Debugger)

Cache Strategy

Cache-Control: public, max-age=3600, s-maxage=86400
  • Edge cache: 24 hours
  • Browser cache: 1 hour
  • Purge on note update

Alternatives Considered

Option Pros Cons
Cloudflare Workers Already using CF, minimal changes, edge-rendered Need to maintain Worker
Static Pre-Generation Simple Doesn't scale, stale content
Meta Tag Injection Quick fix Still CSR, limited SEO benefit
Full framework (Next.js) Built-in SSR Major migration

Labels

enhancement seo performance"

Metadata

Metadata

Assignees

Labels

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions