写在前面:今天这节课玩了个大的------整个 Next.js 博客项目,都是结合 AI 完成的。老师说 Next.js 是"最好的 AI 全栈框架",因为它给 AI 提供了一套约束和上下文:文件放哪、路由怎么建、组件怎么命名,全是约定。AI 拿到这套"乐高积木说明书",写代码又快又稳------这就是所谓的"AI FED harness 落地"。最后我们得到了一个功能完整的博客:学习手册首页、About 发展历程、博客列表、动态路由文章详情、404 页面,App Router 的文件约定、SSG 动态路由、Link 客户端导航全用上了。全程真实代码,一个字符没改。
一、框架是什么:盖房子的蓝图与工具箱
动手之前,老师先讲了个哲学问题------框架(Framework)到底是什么? readme 原话:
"想象为一个建筑蓝图/工具箱,不需要从0开始盖房子。而是提供了地基、墙壁和屋顶的一个基本架构。以前是为开发者所有,现在是AI 也可以用。我们只需要关注组装和装修这个房子,关注业务。"
以前不用框架是什么体验?readme 写得很扎心:
"不使用框架:散乱的积木和工具。图片放哪里?/public。页面放哪里?/app。组件放哪里?/components。"
什么都要自己定规矩,AI 也不知道该听谁的。而用框架:
"使用框架 预制的乐高积木 提供了一系列的约束最佳实践,和AI SDD 文档上下文不谋而合。"
框架 = 一套预制的乐高积木 + 说明书。你不需要从零造砖头,只需要关注"组装和装修"------也就是业务逻辑。
二、为什么说 Next.js 是最好的 AI 全栈框架
readme 的标题就叫《Next.js + AI》,开篇就给了结论:
"基于React的全栈开发框架,最好的Ai 全栈框架,为全栈开发叠加上下文buff。"
而且给了个公式:
"AI 上下文 = 组件 + 响应式业务 + 服务器端渲染"
为什么是 Next.js?readme 列了几条,每条都是"AI 友好"的角度:
| 理由 | 说明 |
|---|---|
| 上下文切换成本 | 传统全栈是 react + Java/Python 两种语言;Next.js 一种语言搞定 |
| claude code/codex 支持最好 | 约束、简化(csr,ssr)开箱即用,AI 上手快 |
| tailwindcss | 原子类名自带语义,特别适合 AI 学习------AI 的语义理解能力直接对齐 |
| 生态超级丰富 | shadcn/ui、ElementUI、ANTD......vibe coding 写组件、引入组件 |
| Vercel | 全球唯一一家 JS 栈 AI coding Agent 以及生态的技术公司,快捷发布、绑定域名 |
最关键的一条在这里:
"使用框架,也给AI 一套约束,一套上下文。AI能够更高效的根据框架给的约束开发项目。"
框架不只约束人类开发者,也约束 AI------AI 拿到约束,产出就更可控。这就是"给全栈开发叠加上下文 buff"的真正含义。
三、项目全景:AI 生成的博客长什么样
思路通了,直接看成品。整个博客项目的文件结构:
text
app/
├── layout.tsx # 根布局:My App + 导航(About / Blog)
├── page.tsx # 首页:Next.js 学习手册
├── not-found.tsx # 404 兜底页
├── about/
│ └── page.tsx # 关于页:发展历程时间线
├── blog/
│ ├── page.tsx # 博客列表页
│ └── [slug]/
│ └── page.tsx # 文章详情页(动态路由)
└── posts.ts # 文章数据 + getPostBySlug
首页那份"学习手册"里,把 App Router 的文件系统路由约定总结得明明白白:
| 约定文件 | 标签 | 职责 |
|---|---|---|
page.tsx |
必选 | 页面入口。目录下必须有它才能被路由访问 |
layout.tsx |
共享 | 布局组件。包裹子路由,切换页面时不会重新渲染 |
loading.tsx |
流式 | 加载 UI。配合 Suspense 实现边加载边渲染 |
not-found.tsx |
兜底 | 404 页面。路由找不到时展示给用户 |
error.tsx |
容错 | 错误 UI。路由抛错时展示,支持局部重置 |
还有那句经典的:
"📁 app / 目录 = 一个路由。新建文件夹 + page.tsx,路由立即生效,无需额外配置。"
约定优于配置,放进正确的文件,路由、布局、加载态就有了------这句话既是说给人听的,也是说给 AI 听的。
四、首页:一份会"长成页面"的学习手册
首页就是这份学习手册的"实体化":把路由约定和核心特性写进数组,map 渲染成卡片。
tsx
const routeConventions = [
{
file: "page.tsx",
tag: "必选",
desc: "页面入口。目录下必须有它才能被路由访问。",
},
{
file: "layout.tsx",
tag: "共享",
desc: "布局组件。包裹子路由,切换页面时不会重新渲染。",
},
// loading.tsx 流式 / not-found.tsx 兜底 / error.tsx 容错 ...
];
配上 metadata:
tsx
export const metadata: Metadata = {
title: "Next.js 学习手册",
description: "Next.js App Router 核心概念与文件系统路由约定",
};
再往下是核心特性卡片:React Server Components(客户端不下载对应 JS,体积更小)、SSR / SSG / ISR(按页面灵活选择渲染策略)、Streaming(首屏更快)、Turbopack(下一代打包器)。学习笔记直接变成了产品页面------这就是把知识做成项目的快乐。
五、动态路由 + SSG:/blog/slug 一篇篇文章
博客的核心是文章详情页------动态路由 [slug]。看 app/blog/[slug]/page.tsx:
tsx
import { notFound } from "next/navigation";
import { getPostBySlug, posts } from "../posts";
export function generateStaticParams() {
return posts.map((post) => ({ slug: post.slug }));
}
interface PostPageProps {
params: Promise<{ slug: string }>;
}
export async function generateMetadata({
params,
}: PostPageProps): Promise<Metadata> {
const { slug } = await params;
const post = getPostBySlug(slug);
if (!post) {
return { title: "文章不存在" };
}
return {
title: post.title,
description: post.excerpt,
};
}
export default async function PostPage({ params }: PostPageProps) {
const { slug } = await params;
const post = getPostBySlug(slug);
if (!post) {
notFound();
}
// ...渲染文章内容
}
三个关键点:
| 函数 | 作用 |
|---|---|
generateStaticParams |
提前把每篇文章的 slug 生成出来 → SSG 静态生成,构建时一次生成所有文章页 |
generateMetadata |
根据 slug 动态生成每篇文章的 title / description → 每篇文章都有自己的 SEO |
notFound() |
文章不存在时调用 → 触发 not-found.tsx |
文章数据存在 posts.ts,Post 接口是 slug / title / excerpt / date / tags / content,还有 getPostBySlug 查询函数。内容更有意思------两篇文章分别是《为什么选择 Next.js 16》和《App Router 文件约定入门》......学什么就写什么,笔记即博客。
六、404 兜底:给用户一个体面的"下台"
路由不存在怎么办?not-found.tsx 登场:
tsx
import Link from "next/link";
export default function NotFound() {
return (
<div className="flex flex-1 flex-col items-center justify-center bg-zinc-50 px-6 py-16 text-center dark:bg-black">
<main className="flex flex-col items-center">
<p className="font-mono text-sm font-semibold tracking-widest text-zinc-500 dark:text-zinc-400">
ERROR 404
</p>
<h1 className="mt-4 text-8xl font-semibold tracking-tight text-zinc-950 sm:text-9xl dark:text-zinc-50">
404
</h1>
<p className="mt-6 max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
这个页面不存在。可能已被移动或删除,也可以是你输错了地址。
</p>
<Link
href="/"
className="mt-10 inline-flex h-12 items-center justify-center rounded-full bg-foreground px-8 text-base font-medium text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc]"
>
返回首页
</Link>
</main>
</div>
);
}
巨大的 404、一句安抚文案、"返回首页"按钮------兜底页不是敷衍,是给用户一个体面的下台。
七、Link 客户端导航:不整页刷新的秘密
页面之间跳转用的是 next/link 的 Link,而不是 <a>。README 把原理讲透了:
"它是客户端导航,无需刷新页面。(前端路由)Hash,HistoryRouter 局部刷新。还是要请求后端的,只是不整页刷新(白一下)。"
"前端导航时,next.js 会自动发一个RSC payload(React Server Component序列化),数据是后端拿的,只是走Ajax 请求,不是浏览器传统的导航。"
原来 Link 跳转不是重新加载页面,而是发一个 RSC payload(服务器组件的序列化数据)------数据还是后端拿的,但走的是 Ajax,页面不整页刷新,不"白一下"。
更狠的是预加载:
"预加载可连接的页面,提升速度。
<link rel="prefetch" href="/blog" />,浏览器空闲时就会提前下载目标页的数据,'秒开'。"
浏览器在空闲时悄悄把目标页面数据下载好,用户点过去直接"秒开"------你以为你在等页面,其实页面早就到了 。README 还顺手科普了 dns-prefetch 和 DNS 解析(domain -> ip 查询,电信服务商的分布式数据库),资源预加载的完整链路。
八、总结:Next.js + AI 的技术地图
| 概念 | 在这节课的角色 |
|---|---|
| 框架 | 蓝图 + 工具箱,以前约束人,现在也约束 AI |
| AI 上下文 | 组件 + 响应式业务 + 服务器端渲染 |
| App Router 约定 | page / layout / loading / not-found / error 五大约定文件 |
| 动态路由 slug | 目录名映射 URL,一个文件夹一个路由 |
| generateStaticParams | 提前生成 slug,SSG 静态生成文章页 |
| generateMetadata | 每篇文章独立的 SEO 元数据 |
| notFound() | 找不到就触发 404 兜底页 |
| Link 组件 | 客户端导航,RSC payload 走 Ajax,不整页刷新 |
| prefetch | 浏览器空闲时预下载目标页,实现"秒开" |
| Vercel | 全球唯一 JS 栈 AI coding Agent 生态公司 |
这节课的答案就一句话:框架是给 AI 的"上下文 buff"------给 AI 一套约束,AI 就能高效地帮你把整个项目写出来。
写在最后
这节课最大的收获,是亲眼看着一个完整的博客项目被 AI 写出来。以前总觉得"框架"是给人类开发者偷懒用的,现在才明白:框架最大的价值之一,是给 AI 一套确定的上下文------文件放哪、路由怎么建、命名什么规范,AI 拿到约束,产出稳定可控。从"学习手册"首页到"发展历程"About 页,从博客列表到 SSG 动态详情,再到 404 兜底,一个能直接部署的 Next.js 16 博客就这么立起来了。这就是 vibe coding 的快乐:你负责"关注业务",AI 负责"组装装修"。
下次面试官问你:"Next.js 的动态路由和静态生成怎么配合?Link 和普通 a 标签有什么区别?"
你可以淡定地说:
"Next.js 的动态路由靠 slug 目录实现,配合 generateStaticParams 可以在构建时把每篇文章的 slug 提前生成,实现 SSG 静态生成;generateMetadata 根据 slug 动态生成每篇文章的 title 和 description,做独立的 SEO;文章不存在时调用 notFound() 触发 not-found.tsx 兜底页。Link 组件是客户端导航,跳转时不需要整页刷新------它会发一个 RSC payload(React Server Component 序列化数据),数据还是从后端拿,但走的是 Ajax 请求;而且 Next.js 会通过 prefetch 在浏览器空闲时预加载目标页数据,实现'秒开'。整套 App Router 的文件约定(page / layout / loading / not-found / error)让路由、加载态、错误处理全部'放对文件就生效',这也是框架给 AI 提供的约束和上下文。"
然后看着面试官满意的表情,心里默念:这波,又稳了。
本文所有代码示例均来自课堂学习资料,真实可运行。