4.7 Next.js 快速上手:创建项目与目录结构
📌 基于 Next.js App Router · 2026-10 更新。Next.js 每年有较大版本更新,具体 API 以你项目里
package.json的版本为准。本节教的是不会变的部分:目录约定、三个命令、以及那条最容易把新手卡住的"use client"规则。
一、本节你会做出什么
你会自己从零创建一个 Next.js 项目(这次搞懂每个选项在问什么),看懂 app/ 目录的约定,并让 pnpm build 第一次通过。
📷 效果位:终端里 build 成功的输出 + 浏览器里的页面
2.2 里你跑过一次 pnpm create next-app,当时是“一路回车”。这次你会知道自己在建什么。
二、开始前你需要
三、跟着做
第 1 步:Next.js 在 React 之外加了什么
4.6 结尾那个类比:React 是发动机,Next.js 是整台车。 具体加了这五样:
| Next.js 提供 | 没有它你要自己做 | 本课哪里用 |
|---|---|---|
| 路由 | 自己写一套“网址 → 显示哪个页面”的逻辑 | 4.8、5.6 |
| 服务端渲染 | 页面得等 JS 跑完才有内容,搜索引擎看不到 | 11.6(SEO) |
| 图片优化 | 手动压缩、手动做不同尺寸 | 5.3 |
| 后端接口 | 单独起一个后端项目 | 7.7、8.3 |
| 构建与部署约定 | 自己配打包工具 | 11.2 |
🔑 第 4 条值得划重点:Next.js 项目里可以直接写后端代码。这意味着第 8、9 章你不需要再学一套新东西——还是这个项目,多加几个文件。这是本课选 Next.js 的主要原因。
第 2 步:创建项目,这次看懂每个选项
cd ~/Documents/ai-course # 换成你的路径pnpm create next-app@latest nextjs-practice💡 第 5 章会用同样的方式创建真正的项目「遇见成都」。这次先拿一个练习项目把流程走明白。
它会问你一串问题。这次别急着回车,看一眼每个在问什么:
| 它问什么 | 在问 | 本课选 |
|---|---|---|
Would you like to use TypeScript? |
要不要类型检查(4.5 讲过的 .tsx) |
Yes(AI 写的代码出错更少) |
Would you like to use ESLint? |
要不要代码规范检查 | Yes |
Would you like to use Tailwind CSS? |
要不要 4.3 学的那套 class | Yes |
Would you like your code inside a src/ directory? |
代码外面要不要多包一层 src/ |
都行(4.5 提过两种都常见) |
Would you like to use App Router? |
用新的路由方式还是旧的 | Yes —— 这一项必须 Yes |
Would you like to use Turbopack? |
用更快的构建工具 | Yes |
Would you like to customize the import alias? |
自定义导入路径别名 | No |
⚠️ 只有 App Router 那一项不能选错。 选 No 会得到旧的
pages/路由,本课后面所有内容(4.8 的路由、5.6 的详情页)都对不上。
选项问完它会下载依赖,1~3 分钟(网络慢的话参考 2.2 第五部分)。
📷 截图位 1:创建过程中的选项列表
第 3 步:跑起来,并认识热更新
cd nextjs-practicepnpm dev浏览器打开 http://localhost:3000。
现在做一件事,体会本地开发最舒服的一点:
- 用编辑器打开
app/page.tsx - 随便改掉一段文字,保存
- 不要刷新浏览器 —— 看着它自己变了
这叫热更新(Hot Reload)。改完就见效,不用刷新、不用重启。
🔑 什么时候必须重启
pnpm dev(这三条记一下,能省很多困惑):
改了什么 要重启吗 页面、组件、样式 ❌ 不用,热更新自己处理 .env.local(环境变量)✅ 必须重启(4.5 提过) 配置文件( next.config.ts等)✅ 必须重启 装了新依赖包 ✅ 必须重启 重启方法:终端里 Ctrl+C(2.1 的刹车),再
pnpm dev。
第 4 步:app/ 目录的文件名约定
这是 Next.js 最核心的设计:文件名本身就是配置。
你在 app/ 里放一个叫特定名字的文件,Next.js 就知道该拿它干什么——不需要你在任何地方注册。
| 文件名 | 是什么 | 必须有吗 |
|---|---|---|
page.tsx |
这个网址对应的页面 | ✅ 有它才有这个页面 |
layout.tsx |
外壳,包着同目录及子目录的所有页面 | 根目录必须有 |
loading.tsx |
加载中显示什么 | 可选 |
not-found.tsx |
404 时显示什么 | 可选 |
error.tsx |
出错时显示什么 | 可选 |
globals.css |
全局样式 | 可选 |
layout.tsx 里有一个必须存在的东西:
export default function RootLayout({ children }) { return ( <html lang="zh-CN"> <body> {/* 这里放每页都有的东西,比如导航 */} {children} {/* ← 页面内容会被塞进这个位置 */} </body> </html> );}{children} 就是那个**“插页面的洞”**。没有它,页面内容无处可去,你会看到一个只有导航和页脚的空壳。
💡 4.5 那条判断现在有了技术解释: 「每页都有的东西放
layout.tsx」—— 因为 layout 包着所有页面,写一次,每页都有。
第 5 步:⚠️ "use client" —— 这一节最该记住的一条
这是 App Router 让零基础学员卡住最多的一个点。 花三分钟理解它,能省你几个小时。
Next.js 里的组件分两种:
| 服务端组件(默认) | 客户端组件 | |
|---|---|---|
| 在哪运行 | 服务器上,渲染好 HTML 发给浏览器 | 浏览器里 |
能用 useState 吗 |
❌ 不能 | ✅ 能 |
能用 onClick 吗 |
❌ 不能 | ✅ 能 |
| 能直接读数据库吗 | ✅ 能(第 9 章) | ❌ 不能 |
| 怎么声明 | 什么都不用写(默认就是) | 文件第一行写 "use client" |
所以会发生这件事:
你让 AI 加一个“点击展开”的功能,它写了 useState 和 onClick,然后页面报错:
Error: useState only works in Client Components.Add the "use client" directive at the top of the file to use it.解法就一行,加在文件最顶上(比所有 import 都靠前):
"use client";
import { useState } from "react";...🔑 记住这个因果: 要交互(点击、输入、状态变化)→ 文件顶部加
"use client"。报错信息其实已经把答案写出来了(
Add the "use client" directive)——这是第 6.1 节「报错信息怎么读」的一个好例子:很多报错自带解法。
什么时候不用加:纯展示的页面和组件(景点介绍、文章内容)保持默认的服务端组件更好——更快、对 SEO 更友好。
💡 实用做法:别纠结该不该加。先不加,报错了再加——报错信息会明确告诉你。或者在规则文件(3.5)里写一条:「需要交互的组件记得加
"use client"」。
第 6 步:三个命令,以及为什么要本地 build 一次
package.json 的 scripts 里(4.5 讲过)有这三个:
| 命令 | 干什么 | 什么时候用 |
|---|---|---|
pnpm dev |
启动开发服务器,带热更新 | 日常开发,用得最多 |
pnpm build |
打包成可部署的产物 | 部署前,以及检查错误 |
pnpm start |
运行打包后的产物 | 本地模拟线上环境 |
现在执行一次 build(先 Ctrl+C 停掉 dev):
pnpm build成功的话,你会看到一张路由表,列出生成了哪些页面。
📷 截图位 2:build 成功的输出,含路由列表
🔑 为什么这一步值得单独教:
pnpm dev能跑,不代表pnpm build能过。dev 模式宽容,build 严格(类型错误、未使用的变量、服务端/客户端组件用错,都可能在这里才暴露)。
4.1 定位表最后一行「本地好的,上线就坏」,一半的情况就是这个 —— 部署平台做的第一件事就是
build,它失败了,网站就上不去。养成习惯:提交或部署之前,本地
pnpm build跑一次。 这一条能帮你省掉很多“部署失败”的排查。
第 7 步:动手——给练习项目加点东西
让 AI 干活,用 3.5 的方式描述。先存档:
git init # 新项目还没初始化 Gitgit add -A && git commit -m "初始化 Next.js 练习项目"然后在项目目录里启动 AI 工具,说:
【做什么】把首页改成一个简单的个人介绍页
【放在哪】app/page.tsx;导航栏放到 app/layout.tsx 里
【什么样】- layout 里加一个顶部导航,显示站点名"我的练习站"- 首页包含:一个大标题、一段自我介绍、一个「点我」按钮- 按钮点击后,下面显示一行"你点了 N 次"(N 会累加)- 用 Tailwind,风格简洁,手机上也要正常
【不要做什么】- 不要新增任何依赖包- 不要改配置文件
【怎么算对】pnpm dev 下点击按钮数字会涨,且 pnpm build 能通过
先告诉我你打算改哪些文件,我确认后再动手。注意观察一件事:按钮需要 useState,所以 AI 应该会给对应文件加上 "use client"。如果它忘了,你会看到第 5 步那条报错——这时你知道该怎么办了。
验收(3.5 的四种验收):
git diff --stat # ③ 改动范围pnpm build # 本节新增的一道关:build 必须过浏览器里点一下按钮(② 操作验收),看控制台有没有红字。都过了就存档:
git add -A && git commit -m "首页改成个人介绍页,加上计数按钮"四、完成的标志是
- 我说得出 Next.js 在 React 之外提供了什么(至少说出路由和“能写后端”两条)
- 我自己创建了一个 Next.js 项目,并且知道 App Router 那一项必须选 Yes
- 我体验了热更新:改完保存,不刷新也变了
- 我知道改
.env.local和配置文件必须重启 dev - 我知道
page.tsx是页面、layout.tsx是外壳 - 我知道
layout.tsx里必须有{children},那是“插页面的洞” - 我理解
"use client":要交互就加在文件第一行 - 我知道服务端组件里不能用
useState和onClick - 我知道
dev/build/start三个命令分别干什么 - 我本地跑过一次
pnpm build并通过了 - 我理解“dev 能跑不代表 build 能过”,且知道这是“部署失败”的常见原因
- 我完成了第 7 步的改造,按钮能计数
五、卡住了看这里
Q:报错 useState only works in Client Components。
第 5 步那一条:在报错文件的最顶部(所有 import 之前)加 "use client";。这是本节最高频的一个问题。
Q:报错 Event handlers cannot be passed to Client Component props 或提到 onClick。
同一个原因——你在服务端组件里写了事件处理。加 "use client"。
Q:pnpm dev 报端口被占用。
2.2 第五部分讲过:找到旧终端 Ctrl+C,或用 pnpm dev -- -p 3001 换端口。
Q:pnpm dev 能跑,但 pnpm build 报一堆错。
这正是要本地 build 的意义。 把完整报错给 AI(用本节提示词 ②)。常见原因:类型错误、"use client" 用错位置、引用了不存在的文件。不要跳过 build 直接部署 —— 部署平台会在同一个地方失败,而那边的日志更难读。
Q:页面一片空白,控制台也没报错。
先看 layout.tsx 里有没有 {children}。少了它,页面内容就不会被渲染出来,而且不报错。
Q:我创建项目时选错了选项(比如 App Router 选了 No)。
练习项目最省事的办法:删掉重建。cd .. 然后 rm -rf nextjs-practice,重新 create 一次。练习阶段重建比修改便宜得多。
Q:那些选项我还是记不住,下次创建怎么办? 用本节提示词 ①,让 AI 给你一条带全部参数的命令,一行搞定,不用交互式选择。
六、本节提示词
① 让 AI 给你一条确定的创建命令(避免下次又在选项里犯错):
我要创建一个新的 Next.js 项目,用 pnpm。要求:TypeScript、Tailwind CSS、ESLint、**App Router**、不自定义 import alias。项目名:【你的项目名】
请给我一条**带上全部参数、不需要交互式回答问题**的完整命令,并逐个参数说明它是什么意思。如果某个参数名在当前版本可能不同,提醒我以 `pnpm create next-app --help` 为准。② build 失败急救(本节最该存的一条):
我的项目 `pnpm dev` 能正常运行,但 `pnpm build` 失败了。
完整的构建输出如下(从命令开始到报错结束,一字不删):【粘贴】
请你:1. 指出是哪个文件、哪一行的问题;2. 用大白话说明这是什么问题,以及**为什么 dev 能过而 build 不能**;3. 给出修复方案,**先告诉我方案不要直接改**;4. 修完之后我应该怎么验证(具体命令)。③ 判断某个组件该不该加 "use client":
这是我的组件代码:【@文件名 或粘贴代码】
请告诉我:1. 它需要加 `"use client"` 吗?为什么?2. 如果需要,加在哪一行(我要确切位置);3. 如果不需要,说明它为什么可以保持服务端组件;4. 有没有办法把需要交互的那一小部分单独拆成客户端组件,让页面其余部分保持服务端渲染? 如果有,说明拆分方案的好处。上一节 ← 4.6 为什么需要前端框架 下一节 → 4.8 Next.js 核心:路由与页面跳转