nextjs
npx skills add https://github.com/lobbi-docs/claude --skill nextjs
Agent 安装分布
Skill 文档
Next.js Skill
Provides comprehensive Next.js development capabilities for modern web applications.
When to Use This Skill
Activate this skill when working with:
- Next.js App Router
- Server Components and Client Components
- API Routes and Server Actions
- Static Site Generation (SSG)
- Server-Side Rendering (SSR)
Project Structure (App Router)
“` app/ âââ layout.tsx # Root layout âââ page.tsx # Home page âââ loading.tsx # Loading UI âââ error.tsx # Error handling âââ not-found.tsx # 404 page âââ globals.css âââ agents/ â âââ page.tsx # /agents â âââ [id]/ â â âââ page.tsx # /agents/[id] â â âââ edit/ â â âââ page.tsx # /agents/[id]/edit â âââ new/ â âââ page.tsx # /agents/new âââ api/ â âââ agents/ â âââ route.ts # /api/agents â âââ [id]/ â âââ route.ts # /api/agents/[id] âââ (dashboard)/ # Route group âââ layout.tsx âââ settings/ âââ page.tsx “`
Server Components (Default)
“`tsx // app/agents/page.tsx – Server Component async function AgentsPage() { // Direct database access (no API needed) const agents = await db.query(‘SELECT * FROM agents’);
return ( Agents {agents.map(agent => ( {agent.name} ))} ); }
export default AgentsPage; “`
Client Components
“`tsx // components/AgentSelector.tsx ‘use client’;
import { useState } from ‘react’;
export function AgentSelector({ agents }: { agents: Agent[] }) { const [selected, setSelected] = useState<string | null>(null);
return ( <select value={selected || ”} onChange={(e) => setSelected(e.target.value)} > Select an agent {agents.map(agent => ( {agent.name} ))} ); } “`
Data Fetching
Server Component Data Fetching
“`tsx
// Automatic request deduplication
async function getAgent(id: string) {
const res = await fetch(${process.env.API_URL}/agents/${id}, {
cache: ‘force-cache’, // Default: cache forever
// cache: ‘no-store’, // Never cache
// next: { revalidate: 60 } // Revalidate every 60s
});
return res.json();
}
export default async function AgentPage({ params }: { params: { id: string } }) { const agent = await getAgent(params.id); return ; } “`
Revalidation
“`tsx // Time-based revalidation export const revalidate = 60; // Revalidate every 60 seconds
// On-demand revalidation import { revalidatePath, revalidateTag } from ‘next/cache’;
async function updateAgent(id: string, data: FormData) { ‘use server’; await db.update(‘agents’, id, data); revalidatePath(‘/agents’); revalidateTag(‘agents’); } “`
Server Actions
“`tsx // app/agents/new/page.tsx import { redirect } from ‘next/navigation’;
async function createAgent(formData: FormData) { ‘use server’;
const name = formData.get(‘name’) as string; const type = formData.get(‘type’) as string;
await db.insert(‘agents’, { name, type });
revalidatePath(‘/agents’); redirect(‘/agents’); }
export default function NewAgentPage() { return ( Claude GPT Create Agent ); } “`
API Routes
“`tsx // app/api/agents/route.ts import { NextRequest, NextResponse } from ‘next/server’;
export async function GET(request: NextRequest) { const searchParams = request.nextUrl.searchParams; const type = searchParams.get(‘type’);
const agents = await db.query( ‘SELECT * FROM agents WHERE type = $1’, [type] );
return NextResponse.json(agents); }
export async function POST(request: NextRequest) { const body = await request.json();
const agent = await db.insert(‘agents’, body);
return NextResponse.json(agent, { status: 201 }); }
// app/api/agents/[id]/route.ts export async function GET( request: NextRequest, { params }: { params: { id: string } } ) { const agent = await db.query(‘SELECT * FROM agents WHERE id = $1’, [params.id]);
if (!agent) { return NextResponse.json({ error: ‘Not found’ }, { status: 404 }); }
return NextResponse.json(agent); } “`
Layouts and Loading States
“`tsx // app/layout.tsx export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( Navigation {children} Footer ); }
// app/agents/loading.tsx export default function Loading() { return Loading agents…; }
// app/agents/error.tsx ‘use client’;
export default function Error({ error, reset, }: { error: Error; reset: () => void; }) { return ( Something went wrong! <button onClick={() => reset()}>Try again ); } “`
Middleware
“`tsx // middleware.ts import { NextResponse } from ‘next/server’; import type { NextRequest } from ‘next/server’;
export function middleware(request: NextRequest) { // Authentication check const token = request.cookies.get(‘token’);
if (!token && request.nextUrl.pathname.startsWith(‘/dashboard’)) { return NextResponse.redirect(new URL(‘/login’, request.url)); }
// Add headers const response = NextResponse.next(); response.headers.set(‘x-custom-header’, ‘value’);
return response; }
export const config = { matcher: [‘/dashboard/:path*’, ‘/api/:path*’], }; “`
Environment Variables
“`bash
.env.local
DATABASE_URL=postgresql://… API_URL=http://localhost:8000
Public (exposed to browser)
NEXT_PUBLIC_APP_URL=http://localhost:3000 “`
“`tsx // Server-only const dbUrl = process.env.DATABASE_URL;
// Client-accessible const appUrl = process.env.NEXT_PUBLIC_APP_URL; “`
Build Commands
“`bash
Development
npm run dev
Production build
npm run build npm start
Static export
npm run build
next.config.js: output: ‘export’
“`