0-introduction
讲师介绍
Scott Moss - Frontend Masters 讲师
- 目前是 Double Zero 公司联合创始人(doublezero.tech)
- 专注于 AI 代理技术,用户只需描述需求,代理自动执行
- 所有项目都使用 Next.js 构建,部署在 Vercel 平台
- 曾任旧金山风投公司投资人,专注 AI 公司投资
- Netflix 前工程师,负责随机创意项目开发
教学理念
核心原则
- 只教授生产环境实际使用的技术
- 基于实际经验和踩过的坑分享见解
- 强调从错误中学习,形成个人观点
学习方法论
- 记忆 vs 学习的区别:真正的学习需要在舒适区边缘实践
- 最佳学习状态:略显不适但可以解决的挑战
- 通过构建实际应用来加深理解
- 鼓励使用资源、提问和查阅文档
课程概览
学习目标
- 覆盖 Next.js 基础知识的 65-75%
- 重点关注通用核心概念
- 其余 25-35% 依据具体用例而定
项目介绍
构建应用:Mode(Linear 应用克隆)
技术栈覆盖
- 身份验证(Auth)
- 静态页面
- 应用程序开发
- API 路由
- Server Actions
- 其他 Next.js 核心功能
课程资源
GitHub 仓库
- 仓库地址:Hendrixer/Next.js-Fundamentals
- 分支结构:
- 每个课程对应不同分支
- 起始分支:课程开始的代码
- 解决方案分支:完成后的代码
学习材料
- 文档格式:Markdown 文件(替代 Notion)
- 位置:直接放在项目中
- 用途:
- 学员学习参考
- 讲师教学大纲
- 完整代码示例
Next.js 发展现状
框架优势
- Vercel 团队持续改进
- 缓存机制更加流畅
- 整体架构更加精简
技术环境
- JavaScript 开发的黄金时期
- AI 技术与前端开发深度融合
- Next.js 在现代 Web 开发中的重要地位
学习建议
实践导向
- 通过构建真实应用学习概念
- 在实践中遇到问题并解决
- 培养独立解决问题的能力
资源利用
- 充分利用 Next.js 官方文档
- 参考课程提供的代码示例
- 积极提问和交流
心态调整
- 接受学习过程中的困难
- 将挑战视为成长机会
- 从错误中总结经验
1-course-project-setup
Next.js 是什么
定义和特点
- Next.js 是一个基于 React 的框架
- React 是 UI 库而不是框架,Next.js 是使用 React 的框架
- 适合构建混合应用(hybrid applications)
混合应用的概念
- 混合应用同时具备静态网站和动态应用的特性
- 包含静态页面(如营销网站)
- 也包含客户端动态功能和服务器端功能
- Next.js 使这种转换变得非常流畅
Next.js 的优势
- 提供了大量开箱即用的功能
- 无需围绕 React 构建自己的框架和意见
- 简化了混合应用的开发过程
环境要求
Node.js 版本要求
- 至少需要 Node.js 20 版本
- 也支持 Bun,但课程统一使用 Node 20
- 推荐使用 NVM (Node Version Manager) 管理 Node 版本
项目演示
静态页面部分
- 功能介绍页面
- 价格页面
- FAQ 页面
- 这些都是静态页面
动态功能部分
- 用户注册/登录功能
- CRUD 操作界面:
- 创建问题
- 查看问题列表
- 编辑问题
- 删除问题
特殊功能
- 包含加载状态显示
- 后台有意添加延迟以展示加载效果
项目设置步骤
1. 克隆和安装
# 克隆项目仓库
git clone [仓库地址]
# 安装依赖包
npm install
2. 切换分支
# 切换到第3课分支开始编码
git checkout 03
3. 环境变量配置
创建 .env 文件
- 项目中有
.env.example文件作为参考 - 需要创建自己的
.env文件 - 环境变量是服务器端的动态变量,用于保护敏感信息
必需的环境变量
-
JWT_SECRET
- 用于身份验证
- 可以设置为任意字符串
- 具体实现不是课程重点
-
DATABASE_URL
- 数据库连接字符串
- 有两种获取方式
4. 数据库设置选项
选项一:本地 Postgres
- 在本地运行 Postgres 服务器
- 创建数据库
- 使用本地数据库 URL
- Mac 上推荐使用 Postgres 应用
选项二:使用 Instagres(推荐)
- 访问
instagres.com/new - 通过机器人验证
- 获得免费的数据库 URL
- 基于 Neon 的无服务器 Postgres 服务
- 数据库会在 1 小时后过期(除非添加到 NEON 账户)
5. 数据库同步
# 同步数据库架构
npm run db:push
命令作用
- 将数据库架构与数据库进行同步
- 首次运行会显示检测到更改
- 后续运行如无更改会显示 "no changes detected"
- 设置完成后无需再次操作
课程结构说明
代码准备情况
- 项目中已包含部分预写代码
- 主要是 Tailwind CSS 样式等基础代码
- 课程专注于 Next.js 特有功能
- 会讲解如何从零开始创建 Next.js 应用
学习重点
- 专注于 Next.js 特定功能
- 不会详细讲解与 Next.js 无关的内容(如具体的身份验证实现)
- 重点学习 Next.js 相关的身份验证部分
2-create-a-next-js-app-from-scratch
前置准备
- 需要先设置数据库和环境变量文件
- 初始应用可能会出现错误,这是故意设置的,用于后续修复练习
使用 NPX 创建 Next.js 应用
NPX 工具介绍
- NPX 允许直接使用 NPM 包而无需全局安装
- 适用于那些不想下载但需要使用的全局包
创建命令
npx create-next-app@canary [项目目录名]
示例:
npx create-next-app@canary todos
@canary表示使用 Canary 版本(最新开发版本)todos是项目目录名
安装配置选项
必选配置项
-
TypeScript:
- 强烈建议选择"是"
- 即使不使用类型,也没有额外负担
-
ESLint:
- 绝对选择"是"
- 代码质量检查工具
-
Tailwind CSS:
- 推荐选择"是"
- Next.js 会安装 Tailwind 4 版本
目录结构选项
- Source 目录嵌入:
- 询问是否将整个应用嵌入 src 目录
- 适合 monorepo 项目
- 个人偏好:选择"否"
路由系统选择
- App Router:
- 必须选择"是"
- 不要使用 Pages Router(除非维护 legacy 项目)
- Next.js 13 的 App Router 虽然口碑不佳,但 Next.js 15 版本已大幅改进
开发工具选项
-
Turbopack:
- 用 Rust 重写的 Webpack 替代品,速度更快
- 建议选择"否"
- 原因:
- 与 Vercel 生产部署不兼容
- 与许多工具的兼容性问题
- 虽然开发模式下性能不错
-
TypeScript 别名: 根据个人需求选择
项目初始化后的配置
Prettier 配置(可选但推荐)
创建 .prettierrc 文件:
{
"semi": false,
"singleQuote": true
}
个人偏好设置:
"semi": false- 禁用分号"singleQuote": true- 使用单引号
启动开发服务器
npm run dev
默认配置:
- 默认端口:3000
- 如果 3000 端口被占用,会自动选择新端口
默认项目结构
生成的核心文件
- 单个首页(index 页面)
- 页面布局文件(layout)
- 默认 CSS 样式(支持深色主题)
- Tailwind 配置(如果选择安装)
项目特点
- 配置方面:完整的工具链配置(Tailwind、ESLint 等)
- Next.js 方面:仅 3 个核心文件,保持简洁
- 在功能性和简洁性之间取得良好平衡
学习建议
- 这是开始 Next.js 开发的最佳方式
- 配置完整但不过度复杂
- 为后续开发提供了良好的基础架构
3-project-structure-config
概述
NextJS 是一个高度规范化的框架,它使用文件系统来实现这些规范。不同的文件名和文件名中的不同字符可以确定不同的功能特性。
App Router vs Pages Router
App Router(推荐)
- 从 NextJS 13 开始引入
- 使用
app目录 - 提供更多灵活性和功能
- 充分利用 Vercel 等平台的新功能
- 建议:从头开始构建项目时始终使用 App 目录
Pages Router(不推荐)
- NextJS 13 之前的方案
- 使用
pages目录 - 语法和功能与 App Router 完全不同
- 虽然更简单,但功能有限
- 仍然受支持,但不建议在新项目中使用
NextJS 特殊目录
NextJS 只对三个目录有特殊处理:
1. App 目录
- 使用 App Router 的主要应用目录
- 包含应用的所有路由和页面
2. Public 目录
- 存放需要在互联网上公开访问的静态资源
- 包括:图片、字体、文件等
- 这些文件可以直接被应用提供服务
3. API 目录
- 用于创建 API 端点
- 其他所有目录都可以随意组织
App 目录中的特殊文件名
核心文件类型
Page 文件
- 文件名:
page - 作用:定义路由页面
- 特点:NextJS 有自己的路由器,无需手动配置路由
- 使用方法:在 app 目录内的目录中创建 page 文件即可自动配置路由
Layout 文件
- 文件名:
layout - 作用:为路由提供布局组件
- 功能:包装页面的 UI 组件,且永不改变
- 本质:就是一个布局容器
辅助文件类型
Loading 文件
- 文件名:
loading - 作用:页面加载时显示的加载屏幕
- 使用场景:在获取数据时显示,直到数据获取完成
Error 文件
- 文件名:
error - 作用:页面出现错误时显示的错误屏幕
- 使用场景:处理页面抛出的异常
其他特殊文件
not-found:404 页面template:模板文件- 认证相关页面(预览版功能)
- 401 等状态码页面
API 路由配置
基本规则
- 文件名:必须叫
route(如:route.ts) - 功能:创建 API 端点
- 技术实现:使用 serverless 函数,每个路由都是一个被调用的函数
重要说明
- 在现代 NextJS 开发中,内部应用通常不需要使用 API 路由
- API 路由主要用于提供外部开发者 API
- 内部数据获取有更高效的方式
常见项目结构模式
推荐的目录组织
app/
├── components/ # 组件目录
├── ui/ # UI组件目录
├── (route-groups)/ # 路由组(NextJS特定功能)
└── ...其他自定义目录
组织原则
- 除了 NextJS 特殊目录外,其他目录可以随意组织
- 遵循团队约定和个人偏好
- 保持结构清晰和逻辑性
核心要点总结
- 目录重要性排序:App 目录 > API 目录 > Public 目录 > 其他自定义目录
- 路由配置:通过文件系统自动配置,无需手动设置
- 灵活性:NextJS 只管理特定目录和文件名,其余完全自由
- 最佳实践:始终使用 App Router,避免使用过时的 Pages Router
4-static-vs-dynamic-routes-and-layouts
静态路由 vs 动态路由
静态路由
定义和特点
- 包含静态信息且不会改变的路由
- NextJS 默认会预渲染这些路由并返回 HTML
- 相当于索引静态网站,永不改变
创建方式示例
app/
└── settings/
└── page.tsx # 创建 /settings 静态路由
- 路由始终是
/settings - 路由本身是静态的(数据可能是动态的,后续会讲到)
动态路由
定义和特点
- 通常包含参数的路由
- 路由路径可以根据参数变化
创建方式示例
app/
└── users/
└── [id]/
└── page.tsx # 创建动态路由 /users/:id
注解方法
- 在目录名中使用方括号
[]包围参数名 - 示例:
[id]文件夹用于用户 ID 参数 - 必须在文件夹内放置
page文件
高级路由模式
Catch All Routes(捕获所有路由)
基本语法
app/
└── docs/
└── [...topic]/
└── page.tsx # 匹配 /docs 的任意子路径
特点
- 使用三个点
...展开语法 + 参数名 - 捕获任意嵌套深度的路径
- 无论嵌套多深都会匹配
可选捕获语法
app/
└── docs/
└── [[...topic]]/
└── page.tsx # 同时匹配 /docs 和任意子路径
- 使用双方括号
[[...]] - 既匹配基础路径(
/docs),也匹配所有子路径
实际应用场景
- 内容型网站(如 Vercel 文档网站)
- URL 结构:
/docs/app+ 各种子主题 - 所有主题页面使用相同的页面布局
- 只是内容不同,避免为每个主题手动创建路由
- 结合预渲染和
getStaticParams使用
Layout(布局)
基本概念
定义
- 包装页面的组件,永不改变
- NextJS 内置的 React 布局解决方案
- 本质上就是你在 React 中使用布局的方式
根布局特点
- 类似于
index.html - 职责是渲染其子组件(即路由)
- 内容永不重新渲染
Layout 的优势
性能优化
- 路由切换时布局不会重新渲染
- 避免导航元素等公共组件的重复渲染
- 防止性能损耗
适用场景
- 导航元素
- 全局样式设置
- 任何在路由间应该保持不变的 UI 组件
Layout 的层次结构
布局继承规则
- 每个路由查找最近的祖先布局
- 必须有根布局(整个应用)
- 布局可以嵌套继承
布局层次示例
app/
├── layout.tsx # 根布局(必需)
├── users/
│ ├── layout.tsx # users特定布局
│ └── [id]/
│ └── page.tsx
└── settings/
├── layout.tsx # settings特定布局
└── page.tsx
- users 和 settings 的布局会嵌套在根布局内
- 形成布局的嵌套结构
Template vs Layout
Template 特点
- 与 Layout 完全相同,但有一个关键区别
- 每次路由切换时都会重新渲染
使用场景
- 布局中包含动画效果
- 需要客户端状态在路由切换时重置
- 任何需要在路由变化时更新的布局逻辑
使用方法
- 将
layout文件名替换为template
Route Groups(路由组)
基本概念
定义
- 允许路由共享布局但不影响 URL 结构
- 使用圆括号
()创建
使用场景示例
需求场景
- 应用包含营销页面(静态页面)和仪表板(实际应用)
- 希望它们有不同的布局
- 不希望 URL 反映这种分组
创建方式
app/
├── (marketing)/
│ ├── layout.tsx # 营销页面布局
│ └── about/
│ └── page.tsx # URL: /about (不是 /marketing/about)
└── (dashboard)/
├── layout.tsx # 仪表板布局
└── users/
└── page.tsx
关键特点
- 圆括号内的名称不会出现在 URL 中
- 允许路由共享公共布局
- 不改变 URL 结构
Route Groups 与 Root Layout 的关系
布局继承
- Route Groups 中的布局仍然继承其他布局
- 始终从最近的祖先继承
Root Layout 的可选性
- 如果使用 Route Groups,可以不需要根目录的根布局
- 可以在 Route Groups 中放置各自的布局
- 每个路由会根据访问的路径使用相应的布局
首页处理
- 可以将首页放在 Route Group 中
- 由于 Route Group 不影响 URL,首页仍然是
/ - 但如果有其他不在 Route Group 中的路由,会因缺少布局而出错
Link 组件
基本使用
重要原则
- 不要使用
<a>标签,使用 Link 组件
功能特点
- 与 anchor 标签功能相同
- 额外提供预取功能
- 实现客户端路由
预取和客户端路由
- 自动预取链接资源
- 实现单页应用的路由切换体验
- 类似于其他路由框架的 Link 组件
导入方式
- 来自 NextJS:
import Link from 'next/link'
5-pages-and-routing-exercise
项目路由结构需求
完整路由清单
根布局
- 根布局(已存在,无需创建)
Auth 路由组
/signin/signup
Marketing 路由组
/(首页)- 其他页面(FAQ、pricing 等,可选)
Dashboard 路由
/dashboard- 包含自己的布局
Issues 路由
/issues/new/issues/:id/edit(动态路由)
创建路由的基本规则
组件导出规则
必须使用默认导出
- 所有特殊文件(page、layout 等)必须使用默认导出
- NextJS 通过默认导出识别要渲染的组件
组件返回值要求
- 每个组件必须返回内容(可以是 null,但必须返回)
- 如果不返回任何内容,应用会报错
文件命名规则对比
App 目录规则
- 路由名称 = 目录名称
- 文件名固定为:
page.tsx、layout.tsx等 - 示例:
signup/page.tsx创建/signup路由
Pages 目录规则(旧版本)
- 路由名称 = 文件名称
- 示例:
signup.tsx创建/signup路由
实际创建过程
Marketing 路由组创建
目录结构
app/
└── (marketing)/
├── layout.tsx
└── page.tsx # 首页 /
Layout 组件示例
export default function MarketingLayout({
children,
}: {
children: React.ReactNode;
}) {
return <div>{children}</div>;
}
关键要点
- Layout 组件必须渲染
children - 如果不渲染 children,页面将只显示布局内容,看不到实际路由
Dashboard 路由创建
目录结构
app/
└── dashboard/
├── layout.tsx
└── page.tsx # /dashboard
特点
- 有自己的独立布局
- 布局会嵌套在根布局内
Auth 路由组创建
目录结构
app/
└── (auth)/
├── signin/
│ └── page.tsx # /signin
└── signup/
└── page.tsx # /signup
路由组特点
- 使用圆括号,不出现在 URL 中
- 访问路径是
/signin,不是/auth/signin
Issues 路由创建
目录结构
app/
└── issues/
├── new/
│ └── page.tsx # /issues/new
└── [id]/
└── edit/
└── page.tsx # /issues/:id/edit
动态路由特点
- 使用方括号
[id]创建动态参数 - 可以访问任意 ID,如:
/issues/123/edit
热模块替换特性
开发体验优势
自动重载
- 添加新路由无需重启服务器
- NextJS 内置热模块替换功能
- 甚至环境变量文件更改也会自动识别
Layout 嵌套机制
嵌套规则
实际演示结果
- 根布局包含营销布局
- 营销布局包含实际页面内容
- 形成:根布局 → 营销布局 → 页面内容
路由冲突问题
冲突场景
- 在根目录和路由组中同时放置
page.tsx - 会产生路由冲突,NextJS 选择最近的路由
避免冲突方法
- 仔细规划路由结构
- 确保同一 URL 路径只有一个 page 文件
- 路由组内的页面不与根目录页面冲突
项目组织建议
目录结构选择
组件位置灵活性
- components 目录可以放在 app 目录外
- app 目录专门用于路由相关文件
- API 目录必须在 app 目录内
根布局使用建议
- 始终保持根布局用于全局设置
- 根布局包含所有应用共同的基础设置(字体、标题等)
- 具体功能区域使用各自的子布局
TypeScript 类型处理
实践态度
- 对框架提供的 props(如 children)可以忽略类型错误
- 对自己创建的组件和函数应该严格添加类型
- 可以使用 React 提供的类型,如
React.ReactNode
6-styling-marketing-auth-pages
NextJS 中的样式方案概述
基本原理
核心观点
- NextJS 中有无限种样式方案
- 因为 NextJS 就是 React,而 React 有无限种样式方案
- 重点是构建营销页面和认证页面(签出体验)
课程重点
- 不会手写大量 CSS 和 HTML 结构
- 通过复制粘贴完成样式部分
- 重点关注 NextJS 相关的预渲染和静态页面概念
CSS Modules
基本概念
定义和作用
- 将 CSS 制作成模块
- 核心优势:CSS 作用域隔离,避免全局冲突
- 为样式创建随机类名值,防止样式冲突
- 只加载组件特定的 CSS,不会加载全部 CSS
工作原理
- CSS 与组件绑定,实现样式作用域
- 避免全局样式污染
- 提高 CSS 加载效率
实际使用示例
文件创建
- 文件命名:
newissues.module.css - 必须包含
.module.标识
CSS 编写
.button {
background-color: red;
}
组件中使用
import styles from "./newissues.module.css";
export default function NewPage() {
return (
<div>
<button className={styles.button}>Hello</button>
</div>
);
}
特点
- 导入的对象属性名对应 CSS 类名
- 提供 TypeScript 类型支持
- 浏览器中显示的类名是随机生成的
适用场景和限制
适用场景
- 纯应用开发
- 需要样式隔离的场景
不适用场景
- 绝对不要在库开发中使用
Global CSS
基本概念
定义和用途
- 全局样式文件
- 适用于所有页面的通用样式
最佳使用场景
- CSS 变量定义
- Tailwind 配置
- 字体设置
- 主题配置
- 在所有页面都需要的样式
使用方法
导入位置
- 建议在根布局(RootLayout)中导入
- 通过根布局的继承机制作用到所有页面
导入语法
import "./globals.css";
使用原则
- 不要滥用全局 CSS
- 不要把组件特定样式放在全局 CSS 中
- 保持全局 CSS 文件精简
- 使用其他方案处理组件样式
Tailwind CSS
推荐理由
强烈推荐使用
- 在服务器端渲染中兼容性好
- 可以使用现成的类名,无需自己编写
优势特点
开发效率
- 节省大量开发时间
- 与 React 服务器组件兼容性好
- 使用预定义类名,无需自己创建
兼容性
- 在各种环境中都能正常工作
- 边缘计算环境
- 服务器端
- 客户端
- 所有环境通用
组件库讨论
Shadcn/ui 评价
优点认可
- 外观设计好
- 开发效率高
- AI 友好(AI 容易理解和使用)
个人观点和质疑
- 困惑点:复制粘贴组件需要自己维护,失去了组件库的本质优势
- 理解角度:从快速开发和完全定制的角度看有价值
适用场景
- 需要完全控制组件定制
- AI 辅助开发
- 快速原型开发
个人选择
当前做法
- 不使用任何组件库
- 只使用 Tailwind
- 需要功能性组件时使用无样式的 headless 组件(如 Ark)
Material UI 评价
历史看法
- 十年前刚出现时很喜欢
- 现在认为太臃肿
缺点
- 过于企业化
- 太有主见性
- 大量定制后失去 Material 特色
- 适合想要 Android 应用外观的场景
CSS-in-JS 方案
基本介绍
常见库
- Styled Components
- 其他 CSS-in-JS 解决方案
不推荐使用的原因
服务器组件兼容性问题
- 在 React 服务器组件中不容易工作
- 依赖库作者的正确实现
维护复杂性
- 需要构建系统确保样式正确放置
- 增加了不必要的复杂性
Styled-jsx
基本介绍
NextJS 内置方案
- NextJS 提供的 CSS-in-JS 解决方案
- 在 JSX 中使用 style 标签
使用方式
<style jsx>{`
.button {
background-color: red;
}
`}</style>
评价和建议
适用场景限制
- 特殊环境下可能有用(如邮件模板)
- 没有完整构建系统的环境
CSS 预处理器
历史回顾
常见预处理器
- Sass/SCSS
- Less
- Stylus(讲师曾经的最爱)
当前建议
不推荐新项目使用
- PostCSS 已经替代了预处理器的功能
遗留项目理解
- 对于遗留项目表示理解
- 但新项目不建议选择预处理器
内联样式(Style 属性)
使用场景
可接受的情况
- 客户端状态绑定到样式
- 动态定位和坐标变化
- 动画库的使用场景
- React Native 开发(必需方式)
不推荐的用法
- 绘制盒子和改变字体
- 作为主要样式方案
设计原则
推荐做法
- 使用 Tailwind 的扩展机制创建自定义样式
- 在 CSS 文件中定义自定义 Tailwind 主题
- 保证跨框架兼容性
优势
- 样式可以在任何框架中使用
- 保证一致的外观和行为
7-static-pages
静态页面概述
什么是静态页面
- 定义:不获取数据或至少不获取任何动态数据的常规页面
- 特点:不针对用户个性化,对所有人都相同
- 优化:静态页面经过高度优化
静态页面识别
在 Next.js 开发模式下,可以通过页面右下角的 Next.js logo 查看页面信息:
- 点击 logo 显示路由信息
- 显示 "route static" 表示该页面为静态页面
- 说明该路径将在构建时或数据重新验证后在后台预渲染
静态页面 vs 动态页面
静态页面场景
- 静态博客文章
- 产品页面
- 营销页面(首页、定价页面等)
- 任何在构建时已知且不会改变的内容
动态页面触发条件
以下情况会使页面变为动态页面:
- 使用动态参数(如
[slug])并在页面中使用该参数 - 访问 cookies
- 显式声明为动态页面
- 使用 suspense
- 包含个性化内容
客户端组件的使用
'use client' 指令
"use client";
- 这是 React 功能,不是 Next.js 特有的
- 用于标识传统的单页应用客户端 React 组件
- 必须显式声明才能使用客户端功能
实际应用场景:时间戳组件
- 问题:在静态页面中显示当前年份的动态值
- 解决方案:使用
'use client'指令,在客户端执行动态计算 - 原因:静态页面会被缓存,动态值每次执行结果不同
页面编译和渲染机制
开发模式下的编译
- 页面只在首次访问时才会被 Next.js 编译
- 首次编译耗时较长(如示例中的 336 毫秒)
- 后续访问直接使用缓存,无需重新编译
- 文件更改时触发热模块重载和重新编译
Turbopack 优势
- 显著提升编译速度
- 特别是在首次编译步骤上效果明显
- 但目前兼容性问题仍需解决
Link 组件使用
基本用法
import Link from "next/link";
<Link href="/pricing">定价</Link>;
核心特性
- 必须包含
href属性 - 类似锚标签的使用方式
- 自动进行客户端路由
- 默认启用预取功能
预取控制
<Link href="/pricing" prefetch={false}>
定价
</Link>
静态页面预渲染 (getStaticParams)
使用场景
- 博客文章页面
- 文档页面
- 任何需要根据外部数据源生成多个静态页面的场景
工作原理
export async function generateStaticParams() {
// 获取所有博客文章
const posts = await fetchAllBlogPosts();
// 返回匹配动态路由的参数数组
return posts.map((post) => ({
slug: post.slug,
}));
}
实现步骤
- 导出
generateStaticParams函数 - 从外部数据源获取所有数据
- 返回包含动态路由参数的对象数组
- Next.js 为每个参数生成对应的静态页面
增量静态再生 (ISR)
概念
- 解决大量静态页面构建时间过长的问题
- 按需生成静态页面,而不是预先生成所有页面
工作机制
- 在
generateStaticParams中只返回最重要的页面(如最新的 50 篇文章) - 当用户访问未预渲染的页面时,服务器端实时渲染
- 渲染完成后页面变为静态页面,后续访问直接使用缓存
优势
- 减少构建时间
- 避免编译无人访问的旧内容
- 平衡性能和构建效率
文件组织最佳实践
特殊文件名
避免使用以下特殊文件名(除非有特定用途):
page.tsxlayout.tsxtemplate.tsxloading.tsxerror.tsx404.tsxnot-found.tsx
组件组织
- 可以在路由目录下放置其他组件文件
- 只要不使用特殊文件名,Next.js 不会将其视为路由文件
- 建议:生产环境中应该合理规划组件结构,避免所有代码都放在一个文件中
性能考虑
构建时间优化
- 大量静态页面会显著增加构建时间
- 可能出现 30-40 分钟的部署时间
- 使用增量静态再生避免编译不必要的内容
开发体验
- 首次访问页面时的编译延迟是正常现象
- 包含数据获取的复杂页面编译时间会更长
- Turbopack 可以显著改善这种体验