laconic-deployer-frontend/standards/blueprints/nextjs-templates.md

442 lines
9.0 KiB
Markdown

# Next.js App Router File Templates
This document provides basic templates for the common file types used in a Next.js application with the App Router. These templates follow the current best practices for Next.js 15.
## Page Templates
### Basic Page (`page.tsx`)
```tsx
import { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Page Title',
description: 'Page description',
}
export default function Page() {
return (
<div>
<h1>Page Content</h1>
{/* Page content goes here */}
</div>
)
}
```
### Dynamic Route Page (`[slug]/page.tsx`)
```tsx
export async function generateMetadata({ params }) {
return {
title: `Page for ${params.slug}`,
description: `Description for ${params.slug}`,
}
}
export default function DynamicPage({ params }) {
const { slug } = params
return (
<div>
<h1>Dynamic Page: {slug}</h1>
{/* Dynamic page content goes here */}
</div>
)
}
```
## Layout Templates
### Root Layout (`layout.tsx`)
```tsx
import { Metadata } from 'next'
import './globals.css'
export const metadata: Metadata = {
title: {
template: '%s | Site Name',
default: 'Site Name',
},
description: 'Site description',
}
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<header>
{/* Header content */}
</header>
<main>{children}</main>
<footer>
{/* Footer content */}
</footer>
</body>
</html>
)
}
```
### Nested Layout (`(dashboard)/layout.tsx`)
```tsx
export default function DashboardLayout({ children }) {
return (
<div className="dashboard-layout">
<nav className="dashboard-nav">
{/* Dashboard navigation */}
</nav>
<div className="dashboard-content">
{children}
</div>
</div>
)
}
```
### Auth Layout with Session Check (`(authenticated)/layout.tsx`)
```tsx
import { redirect } from 'next/navigation'
// This is a Server Component
export default async function AuthLayout({ children }) {
const session = await getSession() // Replace with your auth solution
if (!session) {
redirect('/login')
}
return <>{children}</>
}
```
## Error Handling Templates
### Not Found (`not-found.tsx`)
```tsx
import Link from 'next/link'
export const metadata = {
title: 'Not Found',
description: 'Page not found',
}
export default function NotFound() {
return (
<div className="error-container">
<h1>404 - Page Not Found</h1>
<p>The page you are looking for does not exist.</p>
<Link href="/">
Return to Home
</Link>
</div>
)
}
```
### Error Page (`error.tsx`)
```tsx
'use client' // Error components must be Client Components
import { useEffect } from 'react'
export default function Error({ error, reset }) {
useEffect(() => {
// Log the error to an error reporting service
console.error(error)
}, [error])
return (
<div className="error-container">
<h2>Something went wrong!</h2>
<button
onClick={
// Attempt to recover by trying to re-render the segment
() => reset()
}
>
Try again
</button>
</div>
)
}
```
### Global Error (`global-error.tsx`)
```tsx
'use client'
export default function GlobalError({ error, reset }) {
return (
<html>
<body>
<div className="global-error">
<h2>Something went wrong!</h2>
<button onClick={() => reset()}>Try again</button>
</div>
</body>
</html>
)
}
```
## Loading States
### Loading Component (`loading.tsx`)
```tsx
export default function Loading() {
return (
<div className="loading-container">
<div className="loading-spinner"></div>
<p>Loading...</p>
</div>
)
}
```
## Route Handlers
### API Route (`api/route.ts`)
```ts
import { NextResponse } from 'next/server'
export async function GET(request) {
// Handle GET request
return NextResponse.json({ message: 'Hello World' })
}
export async function POST(request) {
// Handle POST request
const body = await request.json()
return NextResponse.json({ received: body })
}
```
### Dynamic API Route (`api/[slug]/route.ts`)
```ts
import { NextResponse } from 'next/server'
export async function GET(request, { params }) {
const { slug } = params
return NextResponse.json({ slug })
}
```
## Middleware
### Middleware (`middleware.ts`)
Place this file in the root of your project:
```ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
// This function runs before requests are completed
export function middleware(request: NextRequest) {
const currentUrl = request.nextUrl.clone()
// Example: check if user is authenticated
const isAuthenticated = checkAuth(request)
if (!isAuthenticated && currentUrl.pathname.startsWith('/protected')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
// Configure matcher for paths that should trigger middleware
export const config = {
matcher: ['/protected/:path*', '/api/:path*'],
}
// Example auth check function
function checkAuth(request) {
// Implement your auth check logic here
return !!request.cookies.get('auth-token')
}
```
## Utilities - Server Actions
### Form Actions (`actions.ts`)
```ts
'use server'
export async function submitForm(formData: FormData) {
// Validate data
const name = formData.get('name')
const email = formData.get('email')
// Process data
try {
// Save to database or send to API
await saveToDatabase({ name, email })
return { success: true }
} catch (error) {
return { success: false, error: error.message }
}
}
async function saveToDatabase(data) {
// Implementation for database interaction
}
```
## Server Component with Data Fetching
### Data Fetching in Server Component (`dashboard/page.tsx`)
```tsx
// This is a Server Component
export default async function DashboardPage() {
// This data fetching happens on the server
const data = await fetchDashboardData()
return (
<div>
<h1>Dashboard</h1>
<div className="dashboard-stats">
{data.map(item => (
<div key={item.id} className="stat-card">
<h3>{item.title}</h3>
<p>{item.value}</p>
</div>
))}
</div>
</div>
)
}
async function fetchDashboardData() {
// API or database call
const res = await fetch('https://api.example.com/dashboard-data', {
cache: 'no-store' // Don't cache this data
})
if (!res.ok) {
throw new Error('Failed to fetch dashboard data')
}
return res.json()
}
```
## Client Component with Hooks
### Interactive Client Component (`components/Counter.tsx`)
```tsx
'use client' // Mark as Client Component
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
)
}
```
## Parallel Routes
### Parallel Route Layout (`@dashboard/page.tsx` and `@profile/page.tsx`)
In your directory structure:
```
app/
layout.tsx
[user]/
layout.tsx
page.tsx
@dashboard/
page.tsx
@profile/
page.tsx
```
In `[user]/layout.tsx`:
```tsx
export default function UserLayout({ children, dashboard, profile }) {
return (
<div className="user-page">
<div className="sidebar">
{/* Sidebar navigation */}
</div>
<div className="main-content">
{children}
</div>
<div className="dashboard-slot">
{dashboard}
</div>
<div className="profile-slot">
{profile}
</div>
</div>
)
}
```
## Route Interception
### Photo Modal Example (`./(.)photos/[id]/page.tsx`)
The directory structure might look like:
```
app/
photos/
page.tsx
[id]/
page.tsx
(.)photos/
[id]/
page.tsx // This intercepts /photos/[id]
```
In `./(.)photos/[id]/page.tsx`:
```tsx
export default function PhotoModal({ params }) {
const { id } = params
// Fetch photo data based on id
return (
<div className="modal">
<div className="modal-content">
<h2>Photo {id}</h2>
<img src={`/api/photos/${id}`} alt={`Photo ${id}`} />
</div>
</div>
)
}
```
## References
- [Official Next.js Documentation](https://nextjs.org/docs/app)
- [Pages and Layouts](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts)
- [Route Handlers](https://nextjs.org/docs/app/building-your-application/routing/route-handlers)
- [Error Handling](https://nextjs.org/docs/app/building-your-application/routing/error-handling)
- [Loading UI and Streaming](https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming)
- [Metadata API](https://nextjs.org/docs/app/building-your-application/optimizing/metadata)
- [Server Actions](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions)
- [Middleware](https://nextjs.org/docs/app/building-your-application/routing/middleware)