CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Next.js 实战入门/课时/项目创建与目录
RawBlame
课时目录12 节

Next.js 实战入门

  1. 01Next.js 是什么
  2. 02项目创建与目录
  3. 03App Router 与文件路由
  4. 04Server 与 Client 组件
  5. 05数据获取与缓存
  6. 06渲染模式 SSR / SSG / ISR
  7. 07Route Handlers
  8. 08MDX 与课时渲染
  9. 09Tailwind 与样式
  10. 10认证与登录门控
  11. 11读 platform 源码
  12. 12综合练习与部署

项目创建与目录

create-next-app、app/ 目录、配置与 dev 命令。

30 分钟

项目创建与目录

这一课你将能做到

  1. 不看文档就能说清 app/、public/、next.config.ts、middleware.ts 各自放什么
  2. 创建一个带 src/ 目录的项目,并亲手添加页面、组件、工具函数
  3. 配置环境变量,区分 NEXT_PUBLIC_ 前缀和服务端专用变量的安全差异

为什么要学

目录结构就是框架的「语法」。Next.js 的路由、渲染、报错定位,全都建立在文件位置之上:文件放错地方,页面就是 404;配置写错文件,功能就是不开。初学者最常见的困境不是「不会写代码」,而是「不知道这行代码该放哪个文件夹」——本课就是解决这个问题的。

本站 platform 项目你以后要读,它就是标准结构:src/app 放页面与路由、src/components 放组件、src/lib 放工具与 API 封装。现在把「标准结构」刻进肌肉记忆,第 11 课读源码时你会像看自己家一样熟悉。

面试角度,这是一个隐形高频题:「介绍一下你们项目的目录结构 / Next.js App Router 的约定式路由怎么组织」。答得有条理,直接体现你真做过项目。

先建立图像

create-next-app 生成的完整目录,加注释版:

my-first-next/
├── src/                    # 源码根(--src-dir 时才有)
│   ├── app/                # ★ 路由核心:文件夹即 URL
│   │   ├── layout.tsx      # 根布局:所有页面共享的外壳
│   │   ├── page.tsx        # 首页 /
│   │   ├── globals.css     # 全局样式
│   │   └── favicon.ico     # 站点图标
│   ├── components/         # (自己建)可复用组件
│   └── lib/                # (自己建)工具函数、API 封装
├── public/                 # 静态资源:/logo.png 直接 URL 访问
├── next.config.ts          # Next.js 配置:图片域名、重定向、MDX…
├── tsconfig.json           # TypeScript 配置(@/ 别名在这里定义)
├── postcss.config.mjs      # Tailwind/PostCSS 配置
├── package.json            # 依赖与脚本
└── .env.local              # 本地环境变量(不提交 git)

三条记忆钩子:

  • URL 相关 → src/app/:页面、布局、接口都在这,靠文件夹名字生成路由
  • 被 URL 直接引用 → public/:public/cat.png 的访问地址就是 /cat.png
  • 其余全是普通前端项目:components、lib、hooks 想怎么拆怎么拆

跟着做

步骤 1:创建项目

npx create-next-app@latest my-app --typescript --tailwind --eslint --app --src-dir
cd my-app
npm run dev

打开 http://localhost:3000 确认默认首页正常。

步骤 2:添加第一个新页面

在 src/app/about/ 下新建 page.tsx:

export default function AboutPage() {
  return (
    <main className="p-8">
      <h1 className="text-2xl font-bold">关于本站</h1>
      <p className="mt-2 text-gray-600">这是一个 Next.js 学习项目。</p>
    </main>
  );
}

保存后直接访问 http://localhost:3000/about。注意:没有注册路由、没有改任何配置——文件夹名就是 URL。这就是「文件路由」。

步骤 3:建立 components 和 lib 目录

# macOS/Linux
mkdir -p src/components src/lib
# Windows PowerShell
mkdir src\components, src\lib

先建工具函数 src/lib/greeting.ts:

export function greeting(name: string): string {
  const hour = new Date().getHours();
  if (hour < 6) return `夜深了,${name}`;
  if (hour < 12) return `早上好,${name}`;
  if (hour < 18) return `下午好,${name}`;
  return `晚上好,${name}`;
}

再建组件 src/components/WelcomeCard.tsx:

import { greeting } from "@/lib/greeting";

export default function WelcomeCard({ name }: { name: string }) {
  return (
    <div className="rounded-lg border p-4 shadow-sm">
      <h2 className="text-lg font-semibold">{greeting(name)}</h2>
      <p className="mt-1 text-sm text-gray-500">欢迎使用本站。</p>
    </div>
  );
}

在 src/app/about/page.tsx 里使用:

import WelcomeCard from "@/components/WelcomeCard";

export default function AboutPage() {
  return (
    <main className="p-8">
      <h1 className="text-2xl font-bold">关于本站</h1>
      <WelcomeCard name="同学" />
    </main>
  );
}

注意 @/ 前缀:这是 tsconfig.json 里配置的路径别名,指向 src/。本站代码里满屏的 @/components/... 就是它。

步骤 4:认识根布局 layout.tsx

打开 src/app/layout.tsx:

import type { Metadata } from "next";
import "./globals.css";

export const metadata: Metadata = {
  title: "我的学习站",
  description: "Next.js 学习项目",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="zh-CN">
      <body>{children}</body>
    </html>
  );
}

两个关键点:每个页面都会被 <body>{children}</body> 包裹(导航栏、页脚就该放这);metadata 导出会变成 <title> 和 <meta> 标签——SEO 的第一入口。

步骤 5:环境变量

在项目根目录新建 .env.local(该文件默认被 git 忽略):

# 浏览器可见:必须以 NEXT_PUBLIC_ 开头
NEXT_PUBLIC_API_URL=http://localhost:8080

# 仅服务端可见:不加前缀,永远不会打进客户端代码
API_INTERNAL_URL=http://backend-internal:8080
DATABASE_URL=postgresql://user:pass@localhost:5432/db

使用方式:

// 任何地方都能读公开变量
const apiUrl = process.env.NEXT_PUBLIC_API_URL;

// 只有 Server Component / route.ts / lib 的服务端代码能读私密变量
const dbUrl = process.env.DATABASE_URL;

本站 platform 的 src/lib/apiBase.ts 就是这么写的:公开地址用 NEXT_PUBLIC_API_URL,服务端 SSR 时优先走内网直连的 API_INTERNAL_URL,避免绕公网拉数据。改完环境变量必须重启 npm run dev 才生效。

步骤 6:next.config.ts 长什么样

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  images: {
    remotePatterns: [{ protocol: "https", hostname: "images.example.com" }],
  },
  async redirects() {
    return [{ source: "/old-about", destination: "/about", permanent: true }];
  },
};

export default nextConfig;

现在只需知道:图片域名白名单、重定向、MDX 支持(第 8 课会用到这里)都改这个文件。

讲清楚要点

  1. src/app/ 是唯一有魔法的目录:里面的文件名是约定(page.tsx、layout.tsx、后续会见的 route.ts),放错名字就不生效。components/、lib/ 完全自由,叫什么都行。
  2. page.tsx 才生成路由:只建文件夹不建 page.tsx,URL 是 404。反过来,src/app/about/ 里写个 helper.ts 不会变成路由——非约定文件名一律当普通模块。
  3. public 没有构建过程:放进去叫什么,URL 就是什么,适合 favicon、字体、下载文件。需要压缩优化的图片用 next/image(可放 public 或远程)。
  4. 环境变量是「发布时」注入的:不是运行时读的。NEXT_PUBLIC_ 变量在构建时被文本替换进 JS 包——所以绝不能把密钥放 NEXT_PUBLIC_ 变量里,等同公开。
  5. @/ 别名默认指向 src/:深层目录导入不用再 ../../..。看到本站代码 import { getTrack } from "@/lib/api" 就知道是 platform/src/lib/api.ts。

你可能会懵的地方

  • components/、lib/、hooks/ 是 Next.js 规定要建的吗? 不是。Next.js 只规定 app/(和 public/)。components、lib、hooks、services 都是社区习惯,你可以按团队喜好组织。本站就是 src/components + src/lib 这套。

  • page.tsx、layout.tsx 后缀能是 .js 或 .jsx 吗? 可以。.js、.jsx、.tsx、.ts 都认。课程统一用 .tsx(TS + JSX),建议你保持一致。

  • .env.local 和 .env 有什么区别? .env 所有环境加载、可提交 git(放无敏感的默认值);.env.local 本地覆盖、约定不提交(放密钥)。优先级 local > 普通。还有 .env.production 只在生产构建加载。

  • 修改环境变量后为什么页面行为没变? 环境变量在进程启动时读取。必须 Ctrl+C 停掉 dev server 再 npm run dev。这是新手坑频率前三的问题。

  • 我应该在 app/ 目录里写业务逻辑吗? 页面文件(page/layout/route)保持「组装层」:取数据、调组件、返回 JSX。业务逻辑沉到 lib/,页面才清爽。本站的页面普遍很薄,逻辑都在 src/lib/。

错法对照

错法问题正解
src/app/about.tsx 想生成 /about文件路由认文件夹不认散文件建 src/app/about/page.tsx
在 app/ 里建 Page.tsx(大写 P)约定文件名小写,不识别严格用 page.tsx
密钥写进 NEXT_PUBLIC_SECRET会打进客户端 JS,全网可见无前缀变量,仅服务端读取
把图片放进 src/assets 后用 /assets/x.png 引用src 下文件没有 URL放 public/,或用 import img from "@/assets/x.png"
改了 .env.local 不重启就测变量还是旧值重启 dev server

卡点急救

  1. 页面 404:按顺序查——文件夹名拼写?有没有 page.tsx?dev server 是否在跑?URL 是否多了少了斜杠。
  2. Module not found: Can't resolve '@/lib/xxx':路径别名没生效,检查 tsconfig.json 里 "paths": { "@/*": ["./src/*"] };或文件确实不存在/扩展名写错。
  3. 浏览器控制台报 process.env.XXX is undefined:如果是 NEXT_PUBLIC_ 变量→重启 dev;如果是无前缀变量→你把它用在了 Client 组件里,只能改为服务端读取或换公开变量。

面试常问

  • 介绍一下 App Router 项目的目录约定? 核心是 app/ 目录的文件约定:page.tsx 定义路由 UI、layout.tsx 定义嵌套布局、loading.tsx/error.tsx/not-found.tsx 处理加载/错误/404、route.ts 定义 API 接口;[param] 文件夹声明动态段。公共组件、工具函数放在 app 外(如 src/components、src/lib),静态资源放 public/。

  • NEXT_PUBLIC_ 前缀的环境变量有什么风险? 它会在构建时被内联进客户端代码,任何用户查看页面源码/JS 包都能拿到。因此只放公开信息(如 API 地址),所有密钥(数据库连接串、JWT secret、第三方 API key)必须用无前缀变量并只在服务端读取。本站把后端地址设为公开变量、把内部直连地址设为服务端变量,就是这个原则的应用。

  • 为什么推荐 src/ 目录? 把「框架约定的 app/」和「自己的代码」都收进 src,根目录只留配置文件,层次更清晰;同时也避免某些工具误把根目录下的杂散 JS 当源码。纯属工程习惯,不加 src 也完全合法。

自测三问

  1. src/app/blog/page.tsx 和 src/app/blog/index.tsx,哪个会生成 /blog 路由?
  2. 一个第三方 API key,应该放在哪种环境变量里?在哪里读它?
  3. public/logo.svg 对应的访问 URL 是什么?

小结一句话

目录结构即框架语法:app/ 管路由、public/ 管静态资源、lib/components 管你自己的代码,环境变量用前缀区分「公开」与「私密」。

延伸

  • Next.js 官方文档:Project Structure
  • 下一课:深入文件路由——动态段、嵌套布局、Link 跳转。
加载本节练习…
← 上一课Next.js 是什么下一课 →App Router 与文件路由