⚡ Next.js
📋 Overview
Next.js 13+ introduces the App Router, which provides a more intuitive file-system based routing system with React Server Components.
🏗️ App Router Architecture
📁 Directory Structure
src/app/
├── (frontend)/ # Frontend route group
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Home page
│ ├── events/ # Events route
│ │ ├── page.tsx # Events listing
│ │ └── [id]/ # Dynamic route
│ │ └── page.tsx # Individual event
│ └── about/ # About route
│ └── page.tsx # About page
├── (admin)/ # Admin route group
│ ├── layout.tsx # Admin layout
│ └── dashboard/ # Admin dashboard
│ └── page.tsx # Dashboard page
└── api/ # API routes
├── events/ # Events API
│ └── route.ts # Events endpoint
└── health/ # Health check
└── route.ts # Health endpoint🔗 Route Groups
Route groups (parentheses) allow us to organize routes without affecting the URL structure:
tsx
export default function FrontendLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<div className="frontend-layout">
<Header />
<main>{children}</main>
<Footer />
</div>
)
}🖥️ Server vs Client Components
🖥️ Server Components (Default)
Server Components render on the server and send HTML to the client:
tsx
// Server Component - renders on server
async function EventList() {
const events = await getEvents() // Server-side data fetching
return (
<div>
{events.map(event => (
<EventCard key={event.id} event={event} />
))}
</div>
)
}💻 Client Components
Client Components render in the browser and handle interactivity:
tsx
'use client' // Mark as client component
function EventForm() {
const [title, setTitle] = useState('')
const [description, setDescription] = useState('')
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
// Handle form submission
}
return (
<form onSubmit={handleSubmit}>
<input
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Event title"
/>
<textarea
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder="Event description"
/>
<button type="submit">Create Event</button>
</form>
)
}📡 Data Fetching
🖥️ Server-Side Data Fetching
tsx
async function EventsPage() {
const events = await getEvents()
return (
<div>
<h1>Upcoming Events</h1>
<EventList events={events} />
</div>
)
}🔌 API Routes
tsx
import { NextRequest, NextResponse } from 'next/server'
export async function GET(request: NextRequest) {
try {
const events = await getEvents()
return NextResponse.json(events)
} catch (error) {
return NextResponse.json(
{ error: 'Failed to fetch events' },
{ status: 500 }
)
}
}
export async function POST(request: NextRequest) {
try {
const body = await request.json()
const event = await createEvent(body)
return NextResponse.json(event, { status: 201 })
} catch (error) {
return NextResponse.json(
{ error: 'Failed to create event' },
{ status: 500 }
)
}
}🖼️ Image Optimization
Next.js provides automatic image optimization:
tsx
import Image from 'next/image'
function EventImage({ event }: { event: Event }) {
return (
<Image
src={event.imageUrl}
alt={event.title}
width={400}
height={300}
className="rounded-lg"
priority={event.isFeatured} // Load featured images immediately
/>
)
}🔤 Font Optimization
tsx
import { Inter, Poppins } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
variable: '--font-inter'
})
const poppins = Poppins({
weight: ['400', '500', '600', '700'],
subsets: ['latin'],
variable: '--font-poppins'
})
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" className={`${inter.variable} ${poppins.variable}`}>
<body className="font-sans">
{children}
</body>
</html>
)
}⚡ Performance Optimization
✂️ Code Splitting
Next.js automatically code-splits by route and component:
tsx
// Lazy load heavy components
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <div>Loading...</div>,
ssr: false // Disable server-side rendering for client-only components
})📊 Bundle Analysis
bash
# Analyze bundle size
pnpm run build
pnpm run analyze📈 Core Web Vitals
We monitor and optimize for Core Web Vitals:
- LCP (Largest Contentful Paint) - < 2.5s
- FID (First Input Delay) - < 100ms
- CLS (Cumulative Layout Shift) - < 0.1
