Portfolio lucdoro.design było wcześniej na Next.js 14 z SSR, wieloma stronami, ISR, Vercel deploymentem. Wszystko „nowoczesne". Wszystko działało. I wszystko było 3× wolniejsze niż jeden HTML.
Zrobiłem migrację w tydzień. Dziś strona to jeden plik index.html (~165KB) + statyczne asset foldery. Serwuje ją zwykły Apache przed WordPressem (klasyczny hosting CPanel). Poniżej — konkretne liczby i argumenty po każdej stronie.
Metryki przed / po
| Metryka | Next.js SSR | Static HTML |
|---|---|---|
| LCP | 2.4s | 0.3s |
| TTFB | 800ms | 90ms |
| JS bundle | 312KB | 8KB |
| Miesięczny koszt | $20 (Vercel Pro) | $0 (współdzielony hosting) |
| Build time (deploy) | 45s | 2s (scp) |
Argumenty za Next.js
Zanim pojedziemy w krytykę — Next.js jest genialny do:
- Sklepów z dynamiczną nawigacją i koszykiem
- SaaS-ów z tysiącami widoków generowanych z DB
- Zespołów 3+ developerów gdzie routing/state management/testy muszą być scentralizowane
- Aplikacji z SSR-friendly SEO i częstymi zmianami content
Moje portfolio to zero z tych. Jedna osoba, sześć sekcji, aktualizacja raz na miesiąc, żaden state poza scroll position i palette-switcher.
Kiedy static ma sens
- Content stały — teksty rzadko się zmieniają, nie potrzebujesz CMS-a
- Jedna osoba pisze i utrzymuje — brak konfliktu w PR-ach
- Zero user-generated content — brak formularzy zapisu, brak konta użytkownika
- Interakcje proste enough by CSS + vanilla JS je udźwignął
- Hosting ma znaczenie kosztowe (nie chcesz płacić $20/msc za portfolio które ma 300 odwiedzin miesięcznie)
Framework to jest tylko wtedy warty złożoności, kiedy oszczędza więcej czasu niż mnie kosztuje utrzymanie. Dla portfolio jedno-osobowego ten kalkulator wychodzi na minus.
Co konkretnie zrobiłem
1. Wyeksportowałem wszystkie strony Next.js do jednego HTML używając Puppeteer (rendered HTML → save to file, potem manual cleanup)
2. Zainlinowałem CSS (Tailwind → CSS custom properties, ~15KB po minifikacji)
3. Wywaliłem całe frameworkowe JS (React, hooks, next/router, next/image). Zamieniłem na ~200 linii vanilla JS dla:
- Palette switcher (data-palette attribute)
- Theme toggle (data-theme attribute)
- Mobile menu (classList.toggle)
- i18n PL/EN (data-i18n keys)
4. Obrazy — zostawiłem jako standard <img> z loading="lazy" i srcset. Zero Next Image, zero optymalizacji runtime.
5. Deploy: scp index.html lucdoro-web:/home/p567739/public_html/. Bez CI, bez build-stepu, bez Vercela.
Co tracisz
- Automatyczna optymalizacja obrazów — musisz to robić manualnie (ImageMagick, Squoosh)
- Type-safety — nie ma TSX, można się rzeźnąć w klasach CSS bez ostrzeżenia
- Ecosystem — brak react-hook-form, react-query, framer-motion. Musisz pisać ręcznie albo z lekkich libek
- Hot-reload dev — brak. Ale live-server + F5 to nie tragedia
Zabierz z tego: nie wybieraj frameworka bo „wszyscy tak robią". Wybieraj bo rozwiązuje problem który masz. Portfolio jedno-osobowe najczęściej nie ma problemu który React rozwiązuje.
PS. Piszę to na stronie która jest tym samym plikiem, o którym mówię. Meta.