EngineeringSenior DeveloperTechnical Sessions

Session 10: React vs Next.js vs Vite - So Sánh & Khi Nào Dùng Gì

Mục tiêu: Hiểu rõ bản chất, trade-offs, và chọn đúng stack cho từng loại dự án.


1. Bản Chất: Library vs Framework vs Build Tool

React (Library)
├── Chỉ lo UI rendering (components, state, lifecycle)
├── KHÔNG có routing, data fetching, build tool
├── Bạn TỰ chọn: router, state management, bundler, CSS solution
└── Flexible nhất, nhưng phải setup nhiều

Next.js (Full-stack Framework)
├── Built ON TOP of React
├── CÓ SẴN: routing, SSR/SSG, API routes, caching, optimization
├── Opinionated: file-based routing, `app/` directory
└── "Batteries included" - ít quyết định cần đưa ra

Vite (Build Tool + Dev Server)
├── KHÔNG PHẢI framework - thay thế Webpack/CRA
├── React + Vite = SPA (giống CRA nhưng nhanh hơn 10-100x)
├── Kết hợp với bất kỳ library: React, Vue, Svelte, vanilla
└── Focus: DX (Developer Experience), build speed

Key Distinction

❌ "React vs Vite" là SO SÁNH SAI
   → Vite là build tool, React là UI library
   → Đúng ra: "React+Vite (SPA)" vs "Next.js"

✅ So sánh đúng:
   1. React + Vite (SPA)         ← Client-side rendering
   2. Next.js (Full-stack)       ← Server + Client rendering
   3. React + Vite + SSR plugin  ← Custom SSR (hiếm khi cần)

2. Rendering Strategies

Client-Side Rendering (React + Vite)

Browser request → Server trả về HTML rỗng + JS bundle
                      │
                      ▼
              Browser download JS
                      │
                      ▼
              React hydrate → Render UI
                      │
                      ▼
              fetch('/api/data') → Render content
                      │
                      ▼
              User thấy content (chậm!)

Timeline:
[────── Blank page ──────][── Loading spinner ──][── Content ──]
0s                        2s                      3s

Server-Side Rendering (Next.js SSR)

Browser request → Next.js server render HTML + data
                      │
                      ▼
              Browser nhận FULL HTML (content sẵn!)
                      │
                      ▼
              Download JS → Hydrate (interactive)

Timeline:
[── Full content visible ──][── Hydrate ──][── Interactive ──]
0s                          0.5s           1.5s

Static Site Generation (Next.js SSG/ISR)

Build time: Next.js pre-render HTML cho tất cả pages
Deploy: Upload HTML files → CDN

Browser request → CDN trả HTML ngay (0ms server processing!)
                      │
                      ▼
              Hydrate → Interactive

Timeline:
[── Content from CDN ──][── Hydrate ──]
0s                       0.5s

So Sánh Rendering

MetricReact+Vite (CSR)Next.js SSRNext.js SSG/ISR
FCP (First Contentful Paint)2-4s0.5-1.5s0.2-0.5s
TTI (Time to Interactive)3-5s1.5-3s0.5-1.5s
SEO❌ Rất kém✅ Tốt✅ Tốt nhất
Server cost❌ Chỉ static⚠️ Node server✅ CDN only (SSG)
Real-time data✅ Always fresh✅ Fresh⚠️ Stale (ISR delay)
ComplexityThấpTrung bìnhTrung bình

3. Routing

React Router (React + Vite)

tsx
// Bạn TỰ configure routing
import { createBrowserRouter } from 'react-router-dom';

const router = createBrowserRouter([
  {
    path: '/',
    element: <Layout />,
    children: [
      { index: true, element: <Home /> },
      { path: 'products', element: <Products /> },
      { path: 'products/:id', element: <ProductDetail /> },
      { path: '*', element: <NotFound /> },
    ],
  },
]);

// Ưu điểm: Flexible, nested routes, loaders, actions
// Nhược điểm: Manual setup, code-splitting tự config

Next.js File-Based Routing

// Tự động từ file structure - zero config
app/
├── page.tsx              → /
├── products/
│   ├── page.tsx          → /products
│   └── [id]/page.tsx     → /products/:id
└── not-found.tsx         → 404

// Ưu điểm: Zero config, automatic code-splitting, layouts
// Nhược điểm: Rigid structure, complex conventions

So Sánh

FeatureReact RouterNext.js App Router
ConfigCode-basedFile-based
Code-splittingManual (lazy())Automatic
Nested layouts✅ Layout routes✅ layout.tsx
Data loadingloader functionServer Components
Middleware❌ Client-only✅ Edge middleware
Type-safe routes3rd partyExperimental

4. Data Fetching

React + Vite (Client-Side)

tsx
// TanStack Query - recommended cho Vite SPA
const { data, isLoading, error } = useQuery({
  queryKey: ['products', filters],
  queryFn: () => fetch('/api/products').then(r => r.json()),
  staleTime: 5 * 60 * 1000,
});

// Trade-offs:
// ✅ Simple mental model
// ✅ Fine-grained cache control
// ❌ Waterfall: page render → fetch → child render → fetch
// ❌ No SEO for dynamic content

Next.js (Server-Side)

tsx
// Server Component - fetch tại server, zero client JS
async function ProductsPage() {
  const products = await db.product.findMany(); // Direct DB access!
  return <ProductGrid products={products} />;
}

// Trade-offs:
// ✅ No waterfall (data ready before render)
// ✅ SEO: content in initial HTML
// ✅ Zero client JS for data fetching
// ❌ More complex mental model (Server vs Client)
// ❌ Server infrastructure required

5. SEO & Performance Benchmarks

SEO Score (Lighthouse)

MetricReact+Vite (CSR)Next.js SSRNext.js SSG
SEO Score40-6090-10095-100
Performance60-8075-9090-100
AccessibilityTùyTùyTùy
Meta tagsClient-sideServer-renderedPre-built
Open Graph❌ Bots miss JS✅ In HTML✅ In HTML
SitemapManualBuilt-inBuilt-in

Bundle Size (Typical project)

React + Vite SPA:
├── vendor.js (React + ReactDOM): ~140KB gzipped
├── app.js: 50-200KB gzipped
└── Total initial: ~200-350KB gzipped

Next.js:
├── framework.js: ~90KB gzipped (shared runtime)
├── page.js: 10-50KB gzipped (per page!)
├── Server Components: 0KB JS (server-only)
└── Total initial per page: ~100-150KB gzipped

6. Deployment

React + Vite → Static Hosting

bash
# Build
npm run build
# Output: dist/ folder (HTML + JS + CSS)

# Deploy anywhere:
# - Azure Static Web Apps (free tier)
# - Azure Blob Storage + CDN
# - Vercel, Netlify, Cloudflare Pages
# - Nginx serving static files

# ⚠️ SPA routing: cần config fallback to index.html
# Nginx:
# try_files $uri $uri/ /index.html;

Next.js → Node Server / Serverless

bash
# Option 1: Node.js server
npm run build && npm start
# → Cần Node.js runtime, Azure App Service / Container

# Option 2: Vercel (zero-config)
# Git push → auto deploy

# Option 3: Docker
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY .next ./.next
COPY public ./public
EXPOSE 3000
CMD ["npm", "start"]

# Option 4: Static export (SSG only)
# next.config.js: output: 'export'
# → Same as Vite, deploy to static hosting

Azure Hosting Comparison

HostingReact+ViteNext.js SSRNext.js SSG
Static Web Apps✅ Free⚠️ SSR via Functions✅ Free
App ServiceOverkill✅Overkill
Container Apps❌✅ Best❌
Cost~$0/month~$10-50/month~$0/month

7. Decision Matrix

Chọn React + Vite khi:

✅ Internal dashboard / Admin panel (không cần SEO)
✅ Single Page Application phức tạp
✅ Embed vào ứng dụng khác (micro-frontend)
✅ Team muốn full control stack
✅ .NET API đã có sẵn, chỉ cần frontend thuần
✅ Prototype / MVP nhanh

Chọn Next.js khi:

✅ Public-facing website (cần SEO)
✅ eCommerce (product pages cần index)
✅ Marketing site, landing pages
✅ Blog, content platform
✅ Full-stack app (frontend + backend trong 1 project)
✅ Cần SSR/SSG/ISR
✅ Cần Edge Functions, Middleware

Decision Table cho Industry

Dự ánRecommendationLý do
Logistics DashboardReact + ViteInternal, real-time, no SEO
eCommerce StorefrontNext.js (SSG/ISR)SEO critical, product pages
Insurance PortalNext.js (SSR)Public + authenticated, SEO
Finance Trading AppReact + ViteReal-time, internal
Corporate WebsiteNext.js (SSG)SEO, static content
SaaS Admin PanelReact + ViteInternal, complex UI
Blog / Content SiteNext.js (SSG)SEO, content-first
Mobile-first PWAReact + ViteOffline-first, SPA feel

8. Hybrid Approach: .NET + Frontend

Approach 1: Monorepo (.NET API + Next.js)
├── src/
│   ├── Api/           ← .NET Web API
│   └── Web/           ← Next.js
├── shared/
│   └── types/         ← Shared TypeScript types (OpenAPI codegen)
└── docker-compose.yml

Approach 2: Separate repos
├── backend-api/       ← .NET Web API (Azure App Service)
└── frontend/          ← React+Vite hoặc Next.js (Static Web Apps)

Approach 3: .NET serve static files
├── src/
│   ├── Api/           ← .NET Web API
│   └── ClientApp/     ← React+Vite (npm run build → wwwroot)
└── → .NET serve cả API + static files

Tổng Kết Session 10

StackBản chấtBest For
React + ViteSPA, client-renderingDashboards, admin panels, PWAs
Next.jsFull-stack frameworkPublic sites, eCommerce, SEO
Vite (pure)Build toolBất kỳ SPA framework nào

Key Rule: Nếu dự án CẦN SEO → Next.js. Nếu internal app → React + Vite. Nếu cần both → Next.js (SSG for public + CSR for authenticated).