本文是《Next.js 完全指南》系列的速查参考页,适合在开发时快速定位 API 用法和配置选项。如需深入理解,请参考对应章节。
一、文件路由约定
app/
├── page.tsx # / 路由页面
├── layout.tsx # 根布局(包裹所有子路由)
├── loading.tsx # 加载状态(Suspense fallback)
├── error.tsx # 错误边界
├── not-found.tsx # 404 页面
├── template.tsx # 类似 layout 但每次导航重新挂载
├── route.ts # API Route(GET/POST/...)
├── default.tsx # 并行路由默认 fallback
├── global-error.tsx # 全局错误处理(根 layout error)
│
├── blog/
│ ├── page.tsx # /blog
│ ├── layout.tsx # /blog/* 的布局
│ └── [slug]/
│ ├── page.tsx # /blog/:slug
│ ├── loading.tsx
│ └── error.tsx
│
├── (marketing)/ # Route Group(无 URL 前缀)
│ ├── about/
│ │ └── page.tsx # /about
│ └── pricing/
│ └── page.tsx # /pricing
│
├── [locale]/ # 动态段:/en, /zh
│ └── [...catchAll]/ # 捕获所有:/anything/here
│ └── page.tsx
| 文件 | 作用域 | 备注 |
|---|---|---|
page.tsx | 当前路由 | 唯一必需文件 |
layout.tsx | 当前路由及子路由 | 导航时保持状态 |
template.tsx | 当前路由及子路由 | 导航时重新挂载 |
loading.tsx | 当前路由及子路由 | Suspense fallback |
error.tsx | 当前路由及子路由 | 错误边界 |
not-found.tsx | 当前路由 | 404 或 notFound() 触发 |
route.ts | 当前路由 | API endpoint |
二、渲染模式决策树
页面需要动态数据?
├── 否 → 数据是否可能变化?
│ ├── 否 → export const dynamicParams = false;
│ │ # SSG(构建时生成,永不更新)
│ └── 是 → export const revalidate = 3600;
│ # ISR(增量静态再生)
└── 是 → 数据是否用户相关/实时?
├── 是 → export const dynamic = 'force-dynamic';
│ # SSR(每次请求实时渲染)
└── 否 → export const revalidate = 60;
# ISR(定期更新 + 按需失效)
需要流式加载?
└── 部分组件用 Suspense + loading.tsx
# Streaming(渐进式渲染,先骨架后内容)
只有前端交互?
└── page.tsx 中不需要 async
# CSR(纯客户端渲染,"use client" 组件)
| 模式 | 首次访问 | 缓存 | 数据新鲜度 | 适用 | 配置 |
|---|---|---|---|---|---|
| SSG | 构建时 | CDN 永久 | 永不更新 | 法律页/关于 | 默认(无 async fetch) |
| ISR | 首次访问生成 | CDN + TTL | TTL 后后台更新 | 博客/商品页 | revalidate = N |
| SSR | 每次请求 | 无 | 最新 | 用户中心/搜索 | dynamic = 'force-dynamic' |
| Streaming | 渐进式 | 部分缓存 | 流内实时 | 大数据量页 | Suspense + loading.tsx |
| CSR | 客户端渲染 | 浏览器 | 客户端实时 | 后台管理 | "use client" |
三、fetch 与缓存
// 默认行为(Next.js 15):请求记忆 + 数据缓存
fetch('https://api.example.com/data');
// 完全禁用缓存(类似 SSR)
fetch('https://api.example.com/data', { cache: 'no-store' });
// ISR:缓存 1 小时后后台刷新
fetch('https://api.example.com/data', { next: { revalidate: 3600 } });
// 带标签缓存(支持按需失效)
fetch('https://api.example.com/posts', { next: { tags: ['posts'] } });
// 永久缓存(类似 SSG)
fetch('https://api.example.com/static', { cache: 'force-cache' });
// 页面级别缓存控制
export const revalidate = 60; // ISR 60 秒
export const dynamic = 'force-dynamic'; // SSR(无缓存)
export const dynamicParams = false; // 只预生成已知路径
四、Server Actions
// 定义 Server Action(可直接绑定到 <form>)
async function createPost(formData: FormData) {
'use server';
const title = formData.get('title') as string;
await prisma.post.create({ data: { title } });
revalidatePath('/posts');
}
// 带错误处理和返回值的 Server Action
async function submitContact(formData: FormData) {
'use server';
const email = formData.get('email') as string;
if (!email.includes('@')) {
return { error: 'Invalid email' };
}
try {
await sendEmail(email);
return { success: true };
} catch {
return { error: 'Failed to send' };
}
}
// 前端:用 useFormState 处理返回
'use client';
import { useFormState } from 'react-dom';
export default function ContactForm() {
const [state, formAction] = useFormState(submitContact, { error: null });
return (
<form action={formAction}>
<input name="email" type="email" required />
<button type="submit">Send</button>
{state?.error && <p>{state.error}</p>}
{state?.success && <p>Sent!</p>}
</form>
);
}
// useOptimistic:乐观更新
const [optimisticState, addOptimistic] = useOptimistic(
initialState,
(current, newItem) => [...current, newItem]
);
async function handleSubmit(formData: FormData) {
addOptimistic({ id: 'temp', title: formData.get('title') });
await serverAction(formData);
}
五、Metadata API
// page.tsx / layout.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'My Page',
description: 'Page description for SEO',
openGraph: {
title: 'My Page',
description: 'OG description',
images: ['/og-image.jpg'],
},
twitter: {
card: 'summary_large_image',
title: 'My Page',
images: ['/twitter-image.jpg'],
},
robots: {
index: true,
follow: true,
},
alternates: {
canonical: 'https://example.com/page',
languages: {
'en-US': '/en/page',
'zh-CN': '/zh/page',
},
},
};
// 动态 Metadata(基于路由参数)
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
};
}
六、Error 处理
// app/error.tsx(局部错误边界)
'use client';
export default function Error({ error, reset }: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<div>
<h2>Something went wrong</h2>
<p>{error.message}</p>
<button onClick={reset}>Try again</button>
</div>
);
}
// app/global-error.tsx(全局错误)
'use client';
export default function GlobalError({ error, reset }) {
return (
<html>
<body>
<h2>Global Error</h2>
<button onClick={reset}>Reload</button>
</body>
</html>
);
}
// 主动抛出 404
import { notFound } from 'next/navigation';
export default async function Page({ params }) {
const post = await getPost(params.slug);
if (!post) notFound(); // 渲染 not-found.tsx
return <Post post={post} />;
}
七、Middleware
// middleware.ts(项目根目录)
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// 认证检查
const token = request.cookies.get('token')?.value;
if (!token && pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
// i18n 重定向
if (!pathname.startsWith('/en') && !pathname.startsWith('/zh')) {
return NextResponse.redirect(new URL('/en' + pathname, request.url));
}
// URL 重写(URL 不变,内部路由改变)
if (pathname === '/docs') {
return NextResponse.rewrite(new URL('/documentation', request.url));
}
// 注入请求头
const headers = new Headers(request.headers);
headers.set('x-user-country', request.geo?.country || 'US');
return NextResponse.next({ request: { headers } });
}
// 匹配规则
export const config = {
matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};
八、next.config.js / next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
// 独立运行模式(Docker 必需)
output: 'standalone',
// 图片配置
images: {
domains: ['cdn.example.com'],
remotePatterns: [
{ protocol: 'https', hostname: '**.example.com' },
],
formats: ['image/avif', 'image/webp'],
},
// 重写规则
async rewrites() {
return [
{ source: '/old-path', destination: '/new-path' },
{ source: '/api/:path*', destination: 'https://api.example.com/:path*' },
];
},
// 重定向
async redirects() {
return [
{ source: '/about-us', destination: '/about', permanent: true },
];
},
// 请求头
async headers() {
return [
{
source: '/:path*',
headers: [
{ key: 'X-Frame-Options', value: 'DENY' },
],
},
];
},
// TypeScript/ESLint 构建时检查(临时禁用)
typescript: { ignoreBuildErrors: false },
eslint: { ignoreDuringBuilds: false },
// 实验性功能
experimental: {
ppr: true, // 部分预渲染
dynamicIO: true, // 动态 IO(Next.js 15+)
after: true, // after() API
},
};
export default nextConfig;
九、Server/Client 组件边界速查
| 能力 | Server Component | Client Component |
|---|---|---|
| async/await | ✅ | ❌(需用 useEffect + useState) |
| 访问数据库/ORM | ✅ | ❌(通过 API 或 props) |
访问 fs / path | ✅ | ❌ |
headers() / cookies() | ✅ | ❌(通过 API) |
useState / useEffect | ❌ | ✅ |
onClick / onChange | ❌ | ✅ |
window / document | ❌ | ✅ |
localStorage | ❌ | ✅ |
| 第三方库(Framer Motion) | 部分✅ | ✅ |
十、CLI 命令速查
# 创建项目
npx create-next-app@latest my-app --typescript --tailwind --app
# 开发
npm run dev # 启动开发服务器(默认 Turbopack)
npm run dev --turbo # 显式启用 Turbopack
# 构建
npm run build # 生产构建
npm start # 启动生产服务器(需先 build)
# 分析 Bundle
npm install @next/bundle-analyzer
# next.config.js: ANALYZE=true npm run build
# 类型检查
npx tsc --noEmit
相关阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。
「frontend」更多文章
Vue 性能优化指南:虚拟列表、懒加载、渲染优化与 Core Web Vitals
Vue 3 应用性能优化完整策略:虚拟滚动(vue-virtual-scroller)、组件懒加载与异步组件、KeepAlive 缓存、Suspense 异步优化、v-memo 渲染记忆化、响应式性能(shallowRef/toRaw)、Bundle 分析与代码分割、渲染函数优化、以及 Core Web Vitals(LCP/INP/CLS)调优。
Nuxt.js 完全指南:Vue 全栈框架的 SSR、SSG、API 路由与部署实践
Nuxt.js 3 深度实践:文件系统路由、SSR/SSG/ISR 渲染模式、API 路由(Server Routes)、useFetch/useAsyncData 数据获取、中间件与插件、SEO 与 Meta 管理、Nitro 服务端引擎、自动导入、部署到 Vercel/Netlify/Node.js。
Vue 测试深度指南:Vitest + Vue Test Utils + Playwright E2E 与 CI 集成
Vue 3 应用从单元测试到 E2E 的完整测试策略:Vitest + Vue Test Utils 组件测试(mount/emits/slots/async)、Pinia Store Mocking、MSW API 拦截、Playwright 端到端测试、Cypress 组件测试、覆盖率标准与 GitHub Actions CI 集成。