Files
agent-skills/skills/vue-best-practices/reference/perf-ssr-ssg-for-page-load.md
Jason Woltje f5792c40be feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories:
- anthropics/skills: 16 (docs, design, MCP, testing)
- obra/superpowers: 14 (TDD, debugging, agents, planning)
- coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth)
- better-auth/skills: 5 (auth patterns)
- vercel-labs/agent-skills: 5 (React, design, Vercel)
- antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo)
- Plus 13 individual skills from various repos

Mosaic Stack is not limited to coding — the Orchestrator and
subagents serve coding, business, design, marketing, writing,
logistics, analysis, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:27:42 -06:00

4.9 KiB

title, impact, impactDescription, type, tags
title impact impactDescription type tags
Use SSR or SSG for Page Load Critical Applications HIGH Client-side SPAs require JavaScript execution before content appears, severely impacting LCP and INP metrics capability
vue3
performance
ssr
ssg
nuxt
page-load
architecture

Use SSR or SSG for Page Load Critical Applications

Impact: HIGH - Pure client-side SPAs must download, parse, and execute JavaScript before users see content. This significantly delays Largest Contentful Paint (LCP) and impacts Core Web Vitals. For page load-critical apps (marketing sites, e-commerce, content sites), use Server-Side Rendering (SSR) or Static Site Generation (SSG).

Choose your architecture based on your content's nature and page load requirements.

Task Checklist

  • Evaluate if page load performance is critical for your use case
  • Choose SSR for dynamic content that changes per request
  • Choose SSG for content that doesn't change frequently
  • Consider hybrid approaches (SSG for marketing, SPA for app)
  • Use Nuxt.js for streamlined SSR/SSG with Vue

Architecture Decision Guide

Content Type Changes Best Approach Example
Marketing pages Rarely SSG Landing pages, docs
Blog/content On publish SSG with regeneration Blog, documentation
E-commerce catalog Hourly/daily SSG + ISR Product listings
User dashboard Per request SPA (ok) Admin panels
Social feed Real-time SSR or SPA News feed
Authenticated app Per user SPA (ok) Internal tools

Incorrect:

// BAD: Pure client-side SPA for a marketing site
// Users see blank page until JS loads and executes

// main.js
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')  // Nothing visible until this runs

// index.html - Users see empty #app until JS executes
// <div id="app"></div>

Correct:

// GOOD: Use Nuxt.js for SSR/SSG
// nuxt.config.ts
export default defineNuxtConfig({
  // SSG: Pre-render at build time (best for static content)
  ssr: true,
  nitro: {
    prerender: {
      routes: ['/', '/about', '/pricing', '/blog']
    }
  }
})

// Or full SSR for dynamic content
export default defineNuxtConfig({
  ssr: true  // Server renders on each request
})
<!-- pages/index.vue - Works with both SSR and SSG -->
<template>
  <div>
    <HeroSection />
    <FeatureList :features="features" />
    <PricingTable />
  </div>
</template>

<script setup>
// Data fetched at build time (SSG) or request time (SSR)
const { data: features } = await useFetch('/api/features')
</script>

Hybrid Approach: SSG Marketing + SPA App

// nuxt.config.ts - Hybrid rendering
export default defineNuxtConfig({
  routeRules: {
    // Static pages - pre-rendered at build
    '/': { prerender: true },
    '/about': { prerender: true },
    '/pricing': { prerender: true },
    '/blog/**': { prerender: true },

    // Dynamic app sections - client-side only
    '/dashboard/**': { ssr: false },
    '/app/**': { ssr: false },

    // API routes - server-side
    '/api/**': { cors: true }
  }
})

Manual SSR with Vue (without Nuxt)

// server.js - Express with Vue SSR
import express from 'express'
import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'
import App from './App.vue'

const app = express()

app.get('*', async (req, res) => {
  const vueApp = createSSRApp(App)
  const html = await renderToString(vueApp)

  res.send(`
    <!DOCTYPE html>
    <html>
      <head><title>My App</title></head>
      <body>
        <div id="app">${html}</div>
        <script type="module" src="/client.js"></script>
      </body>
    </html>
  `)
})

Performance Impact

Approach Time to First Byte LCP JavaScript Required
Client SPA Fast Slow (waits for JS) Yes, before content
SSR Slower Fast (HTML ready) No, for initial view
SSG Fast (CDN) Fast (HTML ready) No, for initial view

When Client-Side SPA Is Acceptable

  • Internal tools and dashboards (users expect loading)
  • Authenticated applications (initial load happens once)
  • Real-time collaborative apps (WebSocket-heavy)
  • PWAs where offline-first is the priority
  • Complex interactive applications (Figma-like)

Static Site Generation with Vite

// vite.config.js - Using vite-ssg for SSG
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  ssgOptions: {
    script: 'async',
    formatting: 'minify'
  }
})

Reference