Kurs Vue.js · Moduł 15: TypeScript i Nuxt
Koncepcje SSR: SPA vs SSR vs SSG vs ISR
W tej lekcji6
Centrum Dowodzenia NOVA LAB musi dostarczać informacje możliwie najszybciej. Różne strategie renderowania są jak różne systemy łączności stacji - każdy ma swoje zalety w zależności od sytuacji.
SPA - Single Page Application
Tradycyjna aplikacja Vue to SPA (Single Page Application):
- Przeglądarka pobiera pusty HTML
- Ładuje JavaScript (bundle Vue)
- JavaScript renderuje całą stronę w przeglądarce
- Nawigacja odbywa się bez przeładowania strony
1Serwer → [pusty HTML + JS bundle] → Przeglądarka → [renderowanie]Zalety SPA:
- Płynna nawigacja bez przeładowań
- Bogata interaktywność
- Prosty hosting (statyczne pliki)
Wady SPA:
- Wolne pierwsze ładowanie (duży JS bundle)
- Pusta strona do czasu załadowania JS
- Słabe SEO - boty widzą pusty HTML
SSR - Server-Side Rendering
SSR renderuje stronę na serwerze i wysyła gotowy HTML:
- Serwer otrzymuje request
- Vue renderuje komponent na serwerze do HTML
- Wysyła gotowy HTML do przeglądarki
- Przeglądarka wyświetla stronę natychmiast
- JavaScript jest ładowany i "hydratuje" stronę (dodaje interaktywność)
1Request → Serwer [renderuje HTML] → Przeglądarka [wyświetla + hydration]Zalety SSR:
- Szybsze First Contentful Paint (FCP)
- Doskonałe SEO - boty widzą pełny HTML
- Lepsza wydajność na wolnych urządzeniach
Wady SSR:
- Większe obciążenie serwera
- Dłuższy Time to Interactive (TTI)
- Bardziej złożona infrastruktura
SSG - Static Site Generation
SSG generuje HTML w czasie budowania (build time):
- Podczas
npm run build- każda strona jest prerenderowana do HTML - Pliki HTML są gotowe do serwowania
- Brak serwera - zwykły hosting statyczny
- JavaScript hydratuje stronę na kliencie
1Build time → [generuje HTML] → Deploy → CDN → PrzeglądarkaZalety SSG:
- Najszybsza możliwa odpowiedź (pliki z CDN)
- Brak serwera - najtańsze
- Doskonałe SEO
Wady SSG:
- Treść nie zmienia się między buildami
- Każda zmiana wymaga rebuildu
- Nie nadaje się do dynamicznych danych
ISR - Incremental Static Regeneration
ISR łączy SSG i SSR - strony są generowane statycznie, ale mogą się odświeżać:
- Pierwsza wizyta - serwowana strona ze statycznego cache
- Po określonym czasie - strona jest regenerowana w tle
- Następna wizyta dostaje zaktualizowaną wersję
1Request → [cache/CDN] → jeśli stałe → regeneruj w tle → nowa wersjaZalety ISR:
- Szybkość SSG + świeżość SSR
- Automatyczne odświeżanie
Wady ISR:
- Bardziej skomplikowana konfiguracja
- Dane mogą być chwilowo nieaktualne (stale-while-revalidate)
Hydration - klucz do interaktywności
Hydration to proces, w którym Vue "przejmuje" statyczny HTML wygenerowany przez serwer i dodaje do niego interaktywność:
1Serwer: <button>Kliknij</button> ← statyczny HTML
2 ↓ hydration
3Klient: <button @click="handler">Kliknij</button> ← interaktywnyVue porównuje wirtualny DOM z istniejącym HTML i podłącza event handlery, ref-y i reaktywność - bez ponownego renderowania całego DOM.
Kiedy użyć jakiej strategii?
| Strategia | Użyj gdy... |
|---|---|
| SPA | Aplikacja wymaga bogatej interaktywności (dashboard, edytor) |
| SSR | Ważne SEO + dynamiczne dane (sklep, blog z komentarzami) |
| SSG | Treść zmienia się rzadko (dokumentacja, landing page) |
| ISR | Treść zmienia się, ale nie w czasie rzeczywistym (blog, katalog) |
Kod do tej lekcji: App.vue
1<script setup lang="ts">
2import { ref } from 'vue'
3
4type RenderStrategy = 'SPA' | 'SSR' | 'SSG' | 'ISR'
5
6interface StrategyInfo {
7 name: RenderStrategy
8 fullName: string
9 description: string
10 pros: string[]
11 cons: string[]
12 useCase: string
13 color: string
14}
15
16const strategies = ref<StrategyInfo[]>([
17 {
18 name: 'SPA',
19 fullName: 'Single Page Application',
20 description: 'Renderowanie w przegladarce po zaladowaniu JS',
21 pros: ['Plynna nawigacja', 'Bogata interaktywnosc', 'Prosty hosting'],
22 cons: ['Wolne ladowanie', 'Slabe SEO', 'Pusty HTML'],
23 useCase: 'Dashboard, edytor, aplikacja wewnetrzna',
24 color: '#00b4d8'
25 },
26 {
27 name: 'SSR',
28 fullName: 'Server-Side Rendering',
29 description: 'Serwer renderuje HTML i wysyla gotowa strone',
30 pros: ['Szybki FCP', 'Doskonale SEO', 'Lepsza wydajnosc'],
31 cons: ['Obciazenie serwera', 'Dluzszy TTI', 'Zlozona infrastruktura'],
32 useCase: 'Sklep, blog, social media',
33 color: '#00ff88'
34 },
35 {
36 name: 'SSG',
37 fullName: 'Static Site Generation',
38 description: 'HTML generowany w czasie budowania (build)',
39 pros: ['Najszybsza odpowiedz', 'Brak serwera', 'Doskonale SEO'],
40 cons: ['Statyczna tresc', 'Rebuild przy zmianie', 'Nie dla dynamicznych danych'],
41 useCase: 'Dokumentacja, landing page, portfolio',
42 color: '#9b59b6'
43 },
44 {
45 name: 'ISR',
46 fullName: 'Incremental Static Regeneration',
47 description: 'Statyczne strony odswiezane w tle',
48 pros: ['Szybkosc SSG + swiezosc SSR', 'Automatyczne odswiezanie'],
49 cons: ['Skomplikowana konfiguracja', 'Dane chwilowo stale'],
50 useCase: 'Blog, katalog, strona firmowa',
51 color: '#f39c12'
52 }
53])
54
55const selected = ref<RenderStrategy>('SPA')
56
57const current = ref<StrategyInfo>(strategies.value[0])
58
59function selectStrategy(name: RenderStrategy) {
60 selected.value = name
61 current.value = strategies.value.find(s => s.name === name)!
62}
63</script>
64
65<template>
66 <div class="nova-lab">
67 <h1>Strategie Renderowania</h1>
68
69 <div class="tabs">
70 <button
71 v-for="s in strategies"
72 :key="s.name"
73 @click="selectStrategy(s.name)"
74 :class="{ active: selected === s.name }"
75 :style="{ borderColor: s.color }"
76 >
77 {{ s.name }}
78 </button>
79 </div>
80
81 <div class="detail" :style="{ borderColor: current.color }">
82 <h2 :style="{ color: current.color }">{{ current.name }}</h2>
83 <p class="fullname">{{ current.fullName }}</p>
84 <p class="desc">{{ current.description }}</p>
85
86 <div class="lists">
87 <div>
88 <h4 style="color: #00ff88">Zalety</h4>
89 <ul>
90 <li v-for="pro in current.pros" :key="pro">{{ pro }}</li>
91 </ul>
92 </div>
93 <div>
94 <h4 style="color: #e74c3c">Wady</h4>
95 <ul>
96 <li v-for="con in current.cons" :key="con">{{ con }}</li>
97 </ul>
98 </div>
99 </div>
100
101 <div class="use-case">
102 <strong>Zastosowanie:</strong> {{ current.useCase }}
103 </div>
104 </div>
105 </div>
106</template>
107
108<style scoped>
109.nova-lab {
110 background: #0a0e27;
111 color: #00ff88;
112 min-height: 100vh;
113 padding: 20px;
114 font-family: monospace;
115}
116h1 { color: #00ff88; margin-bottom: 15px; }
117h2 { margin-bottom: 4px; }
118.tabs { display: flex; gap: 8px; margin-bottom: 15px; }
119.tabs button {
120 background: rgba(0,180,216,0.1);
121 color: #ccc;
122 border: 2px solid #333;
123 padding: 10px 20px;
124 border-radius: 8px;
125 cursor: pointer;
126 font-family: monospace;
127 font-weight: bold;
128}
129.tabs button.active {
130 background: rgba(0,180,216,0.25);
131 color: white;
132}
133.detail {
134 background: rgba(0,180,216,0.06);
135 border: 2px solid #00b4d8;
136 padding: 20px;
137 border-radius: 12px;
138}
139.fullname { color: #888; font-size: 13px; margin-bottom: 8px; }
140.desc { color: #ccc; margin-bottom: 12px; }
141.lists { display: flex; gap: 20px; margin-bottom: 12px; }
142.lists ul { list-style: none; padding: 0; }
143.lists li { padding: 3px 0; font-size: 13px; color: #ccc; }
144.lists li::before { content: '> '; color: #00b4d8; }
145h4 { margin-bottom: 6px; }
146.use-case {
147 background: rgba(0,255,136,0.08);
148 padding: 10px 14px;
149 border-radius: 8px;
150 font-size: 13px;
151 color: #00b4d8;
152}
153</style>Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Co oznacza SSR (Server-Side Rendering)?
2. Czym jest hydration (hydratacja) w kontekście SSR?
To 2 z 3 pytań do tej lekcji. Pozostałe rozwiążesz w grze.
Zadania praktyczne w grze
- Edytor kodu
Zdefiniuj typ union RenderStrategy i interfejs StrategyInfo.
- Układanie w pionie
Uporządkuj kroki procesu Server-Side Rendering:
- Edytor kodu
Zdefiniuj interfejs CrewMember i typuj stany data, pending, error.
- Układanie w pionie
Ułóż kolejność ładowania w SPA (Single Page Application):
- Klikanie w kolejności
Ułóż strategie renderowania od najszybszego do najwolniejszego First Contentful Paint:
- Edytor kodu
Zdefiniuj typ union Page i typuj nawigację między stronami.