SSR and Performance

Back

Loading concept...

πŸš€ Vue.js Production Ready: SSR and Performance

The Restaurant Kitchen Story 🍳

Imagine you own a restaurant. Every time a customer orders food, you have two choices:

  1. Cook everything from scratch at the table (slow, customer waits)
  2. Prepare dishes in the kitchen first, then serve (fast, customer happy!)

This is exactly how SSR (Server-Side Rendering) vs CSR (Client-Side Rendering) works in Vue.js!


🍽️ SSR vs CSR: Kitchen vs Table Service

What is CSR (Client-Side Rendering)?

Think of CSR like giving your customer raw ingredients and a recipe. They cook at their table!

// CSR: Browser does ALL the work
// 1. User opens website
// 2. Gets empty HTML + JavaScript
// 3. Browser runs JavaScript
// 4. Page finally appears!

The Problem? Customer sees empty plate first. Then waits. And waits…

What is SSR (Server-Side Rendering)?

SSR is like cooking in the kitchen FIRST, then serving a ready meal!

// SSR: Server does the work
// 1. User opens website
// 2. Server runs Vue code
// 3. Sends COMPLETE HTML page
// 4. User sees content INSTANTLY!

The Magic? Customer sees a beautiful dish immediately!

graph TD A["User Opens Website"] --> B{Which Method?} B -->|CSR| C["Empty Page"] C --> D["Download JavaScript"] D --> E["Browser Builds Page"] E --> F["User Finally Sees Content"] B -->|SSR| G["Server Builds Page"] G --> H["User Sees Content Fast!"]

Real Example: Nuxt.js (Vue’s SSR Friend)

// nuxt.config.js
export default {
  // Enable SSR mode
  ssr: true,

  // Your page is ready
  // BEFORE it reaches the user!
}

When to use what?

Use CSR Use SSR
Dashboard apps Blog/News sites
Behind login E-commerce
Fast internet users SEO important

πŸ’§ Hydration: Waking Up the Page

The Sleeping Beauty Story

Remember when SSR sends a complete HTML page? That page is like Sleeping Beauty - it looks beautiful but can’t move!

Hydration is the magic kiss that wakes it up!

graph TD A["Server sends HTML"] --> B["Page looks ready"] B --> C[But buttons don't work yet!] C --> D["Vue loads JavaScript"] D --> E["Hydration happens"] E --> F["Page is ALIVE! Buttons work!"]

What Actually Happens?

// The server sent this HTML:
<button>Click Me!</button>

// But it's just a picture of a button!
// Hydration connects Vue to make it work:

createSSRApp(App).mount('#app')
// Now clicking actually does something!

The Golden Rule

The server HTML and Vue’s expected HTML must match exactly!

// ❌ BAD: Different on server vs client
<p>{{ new Date() }}</p>
// Server: "Dec 30, 10:00:00"
// Client: "Dec 30, 10:00:01"
// MISMATCH! Hydration fails!

// βœ… GOOD: Same everywhere
<p>{{ userData.name }}</p>
// Server: "Alex"
// Client: "Alex"
// Perfect match!

βœ‚οΈ Code Splitting: Don’t Carry Everything!

The Backpack Story

Imagine going to school. Would you carry:

  • ALL your textbooks for the ENTIRE year? πŸŽ’πŸ’€
  • Or just TODAY’s books? πŸŽ’πŸ˜Š

Code Splitting = Only carry what you need RIGHT NOW!

How Vue Does It

// ❌ Without Code Splitting
// User downloads EVERYTHING at once
// Even pages they'll never visit!
import HomePage from './HomePage.vue'
import AboutPage from './AboutPage.vue'
import ContactPage from './ContactPage.vue'
// Downloads: 500KB at start

// βœ… With Code Splitting
// Downloads only when needed!
const HomePage = () => import('./HomePage.vue')
const AboutPage = () => import('./AboutPage.vue')
// Downloads: 100KB at start
// Other pages load when visited

Vue Router Magic

// router/index.js
const routes = [
  {
    path: '/',
    component: () => import('../views/Home.vue')
  },
  {
    path: '/about',
    component: () => import('../views/About.vue')
  }
]
// Each page = separate chunk
// Loaded only when user visits!
graph TD A["User Opens App"] --> B["Load Home Page Only"] B --> C{User Clicks About?} C -->|Yes| D["Load About Page"] C -->|No| E["No Extra Download!"]

🌳 Tree Shaking: Removing Dead Leaves

The Garden Story

Imagine you have a huge tree. Some branches are dead - they have no leaves, no fruit. Do you keep them?

NO! You shake the tree and dead branches fall off!

Tree Shaking does the same for your code!

How It Works

// lodash-library.js (Huge library!)
export function add(a, b) { return a + b }
export function subtract(a, b) { return a - b }
export function multiply(a, b) { return a * b }
export function divide(a, b) { return a / b }
// ... 300 more functions

// your-app.js
import { add } from 'lodash-library'
// You only USE add()!

// BEFORE Tree Shaking:
// Bundle = ALL 300+ functions (huge!)

// AFTER Tree Shaking:
// Bundle = ONLY add() function (tiny!)

Vue 3’s Tree Shaking Power

// βœ… Vue 3: Only imports what you use!
import { ref, computed } from 'vue'
// Bundle only includes ref + computed

// ❌ Vue 2 way (everything included)
import Vue from 'vue'
// Bundle includes ENTIRE Vue library

Make Tree Shaking Work

// βœ… Named imports (tree-shakeable)
import { Button } from 'my-ui-lib'

// ❌ Default imports (NOT tree-shakeable)
import MyUILib from 'my-ui-lib'
const { Button } = MyUILib

😴 Lazy Loading Components: Wake Up When Needed!

The Lazy Cat Story

Imagine a cat sleeping on the couch. Does it wake up for no reason?

NO! It only wakes up when you shake the treat bag!

Lazy Loading = Components sleep until you actually need them!

Basic Lazy Loading

// ❌ Eager Loading (loads immediately)
import HeavyChart from './HeavyChart.vue'

// βœ… Lazy Loading (loads when used)
const HeavyChart = defineAsyncComponent(
  () => import('./HeavyChart.vue')
)

With Loading States

import { defineAsyncComponent } from 'vue'

const HeavyChart = defineAsyncComponent({
  // The actual component
  loader: () => import('./HeavyChart.vue'),

  // Show while loading
  loadingComponent: LoadingSpinner,

  // Wait before showing spinner
  delay: 200,

  // Show if loading fails
  errorComponent: ErrorDisplay,

  // Give up after 30 seconds
  timeout: 30000
})

Real World Example

// Only load modal when button clicked!
<template>
  <button @click="showModal = true">
    Open Settings
  </button>

  <SettingsModal v-if="showModal" />
</template>

<script setup>
import { ref } from 'vue'

// Lazy! Only downloads when
// showModal becomes true
const SettingsModal = defineAsyncComponent(
  () => import('./SettingsModal.vue')
)

const showModal = ref(false)
</script>
graph TD A["Page Loads"] --> B["Modal NOT downloaded"] B --> C{User clicks button?} C -->|No| D["Saved bandwidth!"] C -->|Yes| E["Download Modal NOW"] E --> F["Show Modal"]

πŸ“¦ Bundle Size Optimization: Pack Light, Travel Fast!

The Suitcase Story

You’re going on a weekend trip. Would you bring:

  • A truck full of clothes? πŸš› (Takes forever to load!)
  • One small bag? πŸŽ’ (Quick and easy!)

Bundle optimization = Pack only what matters!

Strategy 1: Analyze Your Bundle

# See what's making your app fat!
npm install -D rollup-plugin-visualizer
// vite.config.js
import { visualizer } from 'rollup-plugin-visualizer'

export default {
  plugins: [
    visualizer({
      open: true,
      filename: 'bundle-stats.html'
    })
  ]
}

Strategy 2: External Libraries

// vite.config.js
export default {
  build: {
    rollupOptions: {
      external: ['moment'],
      output: {
        globals: {
          moment: 'moment'
        }
      }
    }
  }
}
// Load moment.js from CDN instead!

Strategy 3: Smart Imports

// ❌ Import entire library (HUGE)
import moment from 'moment'
// Bundle: +300KB 😱

// βœ… Use lighter alternative
import { format } from 'date-fns'
// Bundle: +2KB 😊

// ❌ Import all icons
import * as Icons from '@heroicons/vue'
// Bundle: +500KB 😱

// βœ… Import only needed icons
import { HomeIcon } from '@heroicons/vue/24/solid'
// Bundle: +1KB 😊

Strategy 4: Compression

// vite.config.js
import viteCompression from 'vite-plugin-compression'

export default {
  plugins: [
    viteCompression({
      algorithm: 'gzip'
    })
  ]
}
// Your 500KB bundle β†’ 100KB gzipped!

The Ultimate Checklist

Action Impact
Use code splitting -40% initial load
Tree shake imports -30% bundle size
Lazy load routes -50% initial load
Compress with gzip -70% transfer size
Use modern formats -20% bundle size
graph TD A["Original Bundle 2MB"] --> B["Code Splitting"] B --> C["1.2MB"] C --> D["Tree Shaking"] D --> E["840KB"] E --> F["Lazy Loading"] F --> G["500KB Initial"] G --> H["Gzip Compression"] H --> I["150KB Final! πŸŽ‰"]

🎯 Quick Summary

Concept What It Does Like…
SSR Server builds page first Kitchen cooking
CSR Browser builds page Table cooking
Hydration Makes SSR page interactive Waking up
Code Splitting Load code in pieces Pack for today
Tree Shaking Remove unused code Dead leaves fall
Lazy Loading Load when needed Cat wakes for treats
Bundle Optimize Make everything smaller Pack light

πŸš€ You Did It!

You now understand how to make Vue.js apps production-ready!

Remember:

  • SSR = Fast first paint, great for SEO
  • Hydration = Makes static HTML interactive
  • Code Splitting = Don’t load everything at once
  • Tree Shaking = Remove what you don’t use
  • Lazy Loading = Load components when needed
  • Bundle Optimization = Keep your app lean and fast

Your users will thank you with faster load times and smoother experiences! πŸŽ‰

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.