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.
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
| Metric | React+Vite (CSR) | Next.js SSR | Next.js SSG/ISR |
|---|
| FCP (First Contentful Paint) | 2-4s | 0.5-1.5s | 0.2-0.5s |
| TTI (Time to Interactive) | 3-5s | 1.5-3s | 0.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) |
| Complexity | Thấp | Trung bình | Trung bình |
3. Routing
React Router (React + Vite)
tsx
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 /> },
],
},
]);
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
| Feature | React Router | Next.js App Router |
|---|
| Config | Code-based | File-based |
| Code-splitting | Manual (lazy()) | Automatic |
| Nested layouts | ✅ Layout routes | ✅ layout.tsx |
| Data loading | loader function | Server Components |
| Middleware | ❌ Client-only | ✅ Edge middleware |
| Type-safe routes | 3rd party | Experimental |
4. Data Fetching
React + Vite (Client-Side)
tsx
const { data, isLoading, error } = useQuery({
queryKey: ['products', filters],
queryFn: () => fetch('/api/products').then(r => r.json()),
staleTime: 5 * 60 * 1000,
});
Next.js (Server-Side)
tsx
async function ProductsPage() {
const products = await db.product.findMany();
return <ProductGrid products={products} />;
}
SEO Score (Lighthouse)
| Metric | React+Vite (CSR) | Next.js SSR | Next.js SSG |
|---|
| SEO Score | 40-60 | 90-100 | 95-100 |
| Performance | 60-80 | 75-90 | 90-100 |
| Accessibility | Tùy | Tùy | Tùy |
| Meta tags | Client-side | Server-rendered | Pre-built |
| Open Graph | ❌ Bots miss JS | ✅ In HTML | ✅ In HTML |
| Sitemap | Manual | Built-in | Built-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
Next.js → Node Server / Serverless
bash
npm run build && npm start
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"]
Azure Hosting Comparison
| Hosting | React+Vite | Next.js SSR | Next.js SSG |
|---|
| Static Web Apps | ✅ Free | ⚠️ SSR via Functions | ✅ Free |
| App Service | Overkill | ✅ | 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ự án | Recommendation | Lý do |
|---|
| Logistics Dashboard | React + Vite | Internal, real-time, no SEO |
| eCommerce Storefront | Next.js (SSG/ISR) | SEO critical, product pages |
| Insurance Portal | Next.js (SSR) | Public + authenticated, SEO |
| Finance Trading App | React + Vite | Real-time, internal |
| Corporate Website | Next.js (SSG) | SEO, static content |
| SaaS Admin Panel | React + Vite | Internal, complex UI |
| Blog / Content Site | Next.js (SSG) | SEO, content-first |
| Mobile-first PWA | React + Vite | Offline-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
| Stack | Bản chất | Best For |
|---|
| React + Vite | SPA, client-rendering | Dashboards, admin panels, PWAs |
| Next.js | Full-stack framework | Public sites, eCommerce, SEO |
| Vite (pure) | Build tool | Bấ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).