vercel-development

安装量: 78
排名: #9982

安装

npx skills add https://github.com/mindrally/skills --skill vercel-development

Vercel Development Best Practices Overview

This skill provides comprehensive guidelines for developing and deploying applications on Vercel, with a focus on Next.js, React Server Components, Edge Functions, and the Vercel AI SDK.

Core Principles Write concise, technical TypeScript code with accurate examples Use functional and declarative programming patterns; avoid classes Minimize 'use client', 'useEffect', and 'setState'; favor React Server Components (RSC) Implement responsive design with Tailwind CSS using mobile-first approach Optimize for Core Web Vitals and performance Project Structure my-app/ ├── app/ # App Router pages and layouts │ ├── (auth)/ # Route groups │ ├── api/ # API routes │ ├── layout.tsx # Root layout │ └── page.tsx # Home page ├── components/ # React components │ ├── ui/ # UI primitives │ └── features/ # Feature components ├── lib/ # Utility functions ├── hooks/ # Custom React hooks ├── types/ # TypeScript types ├── public/ # Static assets └── vercel.json # Vercel configuration

Next.js App Router Guidelines File Naming Conventions Use lowercase with dashes for directories (e.g., components/auth-wizard) Prefer named exports for components and functions Use page.tsx for route pages, layout.tsx for layouts Use loading.tsx for loading states, error.tsx for error boundaries Server Components (Default) // app/users/page.tsx import { getUsers } from '@/lib/data';

export default async function UsersPage() { const users = await getUsers();

return (

Users

    {users.map(user => (
  • {user.name}
  • ))}
); }

Client Components (When Needed) 'use client';

import { useState } from 'react';

export function Counter() { const [count, setCount] = useState(0);

return ( ); }

TypeScript Standards Type Definitions // Use interfaces over types for object shapes interface User { id: string; name: string; email: string; createdAt: Date; }

// Use types for unions and complex types type Status = 'pending' | 'active' | 'inactive';

// Avoid enums; use const objects instead const STATUS = { PENDING: 'pending', ACTIVE: 'active', INACTIVE: 'inactive', } as const;

type StatusValue = typeof STATUS[keyof typeof STATUS];

Component Props interface ButtonProps { children: React.ReactNode; variant?: 'primary' | 'secondary' | 'ghost'; size?: 'sm' | 'md' | 'lg'; disabled?: boolean; onClick?: () => void; }

export function Button({ children, variant = 'primary', size = 'md', disabled = false, onClick, }: ButtonProps) { // Implementation }

API Routes Route Handlers // app/api/users/route.ts import { NextRequest, NextResponse } from 'next/server'; import { z } from 'zod';

const CreateUserSchema = z.object({ name: z.string().min(1), email: z.string().email(), });

export async function GET(request: NextRequest) { const users = await getUsers(); return NextResponse.json(users); }

export async function POST(request: NextRequest) { try { const body = await request.json(); const validated = CreateUserSchema.parse(body);

const user = await createUser(validated);
return NextResponse.json(user, { status: 201 });

} catch (error) { if (error instanceof z.ZodError) { return NextResponse.json( { error: 'Validation failed', details: error.errors }, { status: 400 } ); } return NextResponse.json( { error: 'Internal server error' }, { status: 500 } ); } }

Edge Runtime // app/api/edge-function/route.ts export const runtime = 'edge';

export async function GET(request: Request) { return new Response(JSON.stringify({ message: 'Hello from the edge!' }), { headers: { 'Content-Type': 'application/json' }, }); }

Vercel AI SDK Integration Streaming Chat UI 'use client';

import { useChat } from 'ai/react';

export function Chat() { const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({ api: '/api/chat', });

return (

{messages.map(message => (

{message.content}

))}

  <form onSubmit={handleSubmit}>
    <input
      value={input}
      onChange={handleInputChange}
      placeholder="Type a message..."
      disabled={isLoading}
    />
  </form>
</div>

); }

AI API Route // app/api/chat/route.ts import { openai } from '@ai-sdk/openai'; import { streamText } from 'ai';

export async function POST(request: Request) { const { messages } = await request.json();

const result = await streamText({ model: openai('gpt-4-turbo'), messages, system: 'You are a helpful assistant.', });

return result.toDataStreamResponse(); }

Error Handling for AI import { openai } from '@ai-sdk/openai'; import { streamText } from 'ai';

export async function POST(request: Request) { try { const { messages } = await request.json();

const result = await streamText({
  model: openai('gpt-4-turbo'),
  messages,
});

return result.toDataStreamResponse();

} catch (error) { // Handle rate limiting if (error.message?.includes('rate limit')) { return new Response('Rate limit exceeded. Please try again later.', { status: 429, }); }

// Handle quota exceeded
if (error.message?.includes('quota')) {
  return new Response('API quota exceeded.', { status: 402 });
}

// Fallback to alternative model
console.error('Primary model failed:', error);
return new Response('Service temporarily unavailable.', { status: 503 });

} }

Data Fetching Server-Side Data Fetching // Fetch data in Server Components async function getData() { const res = await fetch('https://api.example.com/data', { next: { revalidate: 3600 }, // Cache for 1 hour });

if (!res.ok) { throw new Error('Failed to fetch data'); }

return res.json(); }

export default async function Page() { const data = await getData(); return

{/ Render data /}
; }

URL State Management // Use URL query parameters for server state import { useSearchParams, useRouter } from 'next/navigation';

export function Filters() { const searchParams = useSearchParams(); const router = useRouter();

const updateFilter = (key: string, value: string) => { const params = new URLSearchParams(searchParams); params.set(key, value); router.push(?${params.toString()}); };

return (/ Filter UI /); }

Performance Optimization Image Optimization import Image from 'next/image';

export function Hero() { return ( Hero image ); }

Dynamic Imports import dynamic from 'next/dynamic';

// Lazy load heavy components const HeavyChart = dynamic(() => import('@/components/heavy-chart'), { loading: () =>

Loading chart...
, ssr: false, // Disable SSR if needed });

Suspense Boundaries import { Suspense } from 'react';

export default function Page() { return (

Dashboard

}>
); }

Error Handling Error Boundaries // app/error.tsx 'use client';

export default function Error({ error, reset, }: { error: Error & { digest?: string }; reset: () => void; }) { return (

Something went wrong!

); }

Global Error Handler // app/global-error.tsx 'use client';

export default function GlobalError({ error, reset, }: { error: Error & { digest?: string }; reset: () => void; }) { return ( <html> <body>

Something went wrong!

</body> </html> ); }

Vercel Configuration vercel.json { "framework": "nextjs", "regions": ["iad1"], "crons": [ { "path": "/api/cron/cleanup", "schedule": "0 0 * * " } ], "headers": [ { "source": "/api/(.)", "headers": [ { "key": "Access-Control-Allow-Origin", "value": "*" } ] } ] }

Environment Variables // Use environment variables for sensitive data const apiKey = process.env.API_KEY; const publicUrl = process.env.NEXT_PUBLIC_APP_URL;

// Validate required env vars if (!apiKey) { throw new Error('API_KEY environment variable is required'); }

Deployment Preview Deployments Every pull request gets a preview deployment Use preview URLs for testing and review Share preview links with stakeholders Production Deployment

Connect repo to Vercel (one-click from GitHub)

Or use Vercel CLI

vercel --prod

Edge Config import { get } from '@vercel/edge-config';

export async function getFeatureFlag(flag: string) { const flags = await get('featureFlags'); return flags?.[flag] ?? false; }

UI and Styling Tailwind CSS Setup // Use mobile-first responsive design export function Card({ children }: { children: React.ReactNode }) { return (

{children}
); }

Shadcn UI Components import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog';

export function ConfirmDialog() { return (

Are you sure?

); }

Accessibility Best Practices export function AccessibleButton() { return ( ); }

Common Pitfalls to Avoid Using 'use client' unnecessarily Not implementing proper error boundaries Ignoring Core Web Vitals optimization Not using TypeScript strictly Hardcoding environment variables Missing Suspense boundaries for async components Not optimizing images Ignoring accessibility requirements

返回排行榜