项目结构与配置详解
详细解析 Next.js App Router 的目录结构、核心配置文件及最佳实践。
📚 学习目标
学完这篇文章后,你将能够:
- 理解 Next.js App Router 的目录结构
- 掌握本项目的文件组织方式
- 了解核心配置文件的作用
- 学会使用路径别名
@/ - 掌握环境变量配置方法
前置知识
在开始学习之前,建议先阅读:
你需要了解:
- 基本的文件和目录概念
- JSON 配置文件格式
1️⃣ Next.js App Router 目录结构
1.1 app/ 目录详解
app/ 目录是 Next.js App Router 的核心,所有路由和页面都在这里。
核心文件说明
app/
├── page.tsx # 主页(/)
├── layout.tsx # 全局布局
├── globals.css # 全局样式
│
├── api/ # API Routes(后端接口)
│ ├── chat/
│ │ ├── route.ts # POST /api/chat - 聊天流式接口
│ │ └── sessions/
│ │ └── route.ts # GET/POST/PATCH/DELETE - 会话管理
│ ├── artifacts/ # Canvas 工件 API
│ │ └── [id]/
│ │ └── route.ts # GET/DELETE 工件操作
│ └── auth/ # 认证相关 API
│ ├── callback/
│ │ └── route.ts # OAuth 回调
│ └── login/
│ └── route.ts # 用户登录
│
├── components/ # React 组件(前端 UI)
│ ├── ChatHeader.tsx # 聊天头部
│ ├── MessageList.tsx # 消息列表
│ ├── MessageBubble.tsx # 单条消息气泡
│ ├── ChatInput.tsx # 聊天输入框
│ ├── SessionSidebar.tsx # 会话侧边栏
│ ├── ProtectedRoute.tsx # 路由保护组件
│ ├── canvas/ # Canvas 相关组件
│ │ ├── CanvasPanel.tsx # Canvas 面板
│ │ └── ...
│ └── ...
│
├── services/ # 业务逻辑层
│ ├── chat.service.ts # 聊天服务
│ ├── artifact.service.ts # 工件服务
│ ├── session.service.ts # 会话服务
│ └── README.md # 服务层文档
│
├── database/ # 数据访问层
│ ├── sessions.ts # 会话数据操作
│ ├── artifacts.ts # 工件数据操作
│ └── messages.ts # 消息数据操作
│
├── hooks/ # 自定义 React Hooks
│ ├── useChatMessages.ts # 消息状态管理
│ ├── useSessionManager.ts # 会话管理
│ ├── useChatHistory.ts # 历史记录加载
│ ├── useSendMessage.ts # 消息发送
│ └── useCanvasArtifacts.ts # Canvas 工件管理
│
├── contexts/ # React Context(全局状态)
│ └── AuthContext.tsx # 认证上下文
│
├── middleware/ # 中间件
│ └── auth.ts # 认证中间件(withAuth)
│
└── agent/ # LangGraph AI 引擎
├── chatbot.ts # 状态图定义
├── state.ts # 状态定义
└── tools/ # AI 工具
├── search.ts # 搜索工具
├── image-gen.ts # 图片生成
└── ...1.2 路由与文件的关系
Next.js 使用文件系统路由,文件路径自动映射到 URL。
| 文件路径 | URL 路由 | 说明 |
|---|---|---|
app/page.tsx | / | 首页 |
app/login/page.tsx | /login | 登录页 |
app/deepresearch/page.tsx | /deepresearch | 深度研究页 |
app/artifact/[id]/page.tsx | /artifact/123 | 动态路由 |
app/api/chat/route.ts | /api/chat | POST 接口 |
app/api/artifacts/[id]/route.ts | /api/artifacts/123 | 动态 API |
2️⃣ 核心配置文件详解
2.1 next.config.ts - Next.js 配置
文件位置:next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
reactStrictMode: false, // 禁用 React 严格模式
typescript: {
// 在构建时忽略 TypeScript 类型错误
ignoreBuildErrors: true,
},
experimental: {
// 使用系统 TLS 证书以解决网络问题
turbopackUseSystemTlsCerts: true,
},
};
export default nextConfig;配置项详解
| 配置项 | 值 | 作用 |
|---|---|---|
reactStrictMode | false | 禁用 React 严格模式(开发模式下的额外检查) |
typescript.ignoreBuildErrors | true | 构建时忽略 TypeScript 错误(开发阶段使用) |
experimental.turbopackUseSystemTlsCerts | true | 使用系统 TLS 证书(解决某些网络请求问题) |
注意事项:
ignoreBuildErrors: true仅用于开发阶段,生产环境建议设为falseturbopackUseSystemTlsCerts是实验性配置,可能与某些环境不兼容
2.2 tsconfig.json - TypeScript 配置
文件位置:tsconfig.json
{
"compilerOptions": {
"target": "ES2017", // 编译目标
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true, // 允许导入 JS 文件
"skipLibCheck": true, // 跳过库文件类型检查
"strict": true, // 启用严格模式
"noEmit": true, // 不生成输出文件
"esModuleInterop": true, // ES 模块互操作
"module": "esnext", // 模块系统
"moduleResolution": "bundler", // 模块解析策略
"resolveJsonModule": true, // 允许导入 JSON
"isolatedModules": true, // 每个文件独立编译
"jsx": "react-jsx", // JSX 转换方式
"incremental": true, // 增量编译
"plugins": [{ "name": "next" }], // Next.js 插件
"paths": {
// 路径别名配置
"@/*": ["./*"]
}
},
"include": [
// 包含的文件
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": ["node_modules"] // 排除的文件
}重要配置说明
路径别名(paths):
"paths": {
"@/*": ["./*"]
}这个配置允许你使用 @/ 前缀来导入项目根目录下的文件。
使用示例:
// 不使用路径别名
import { ChatHeader } from '../app/components/ChatHeader';
// 使用路径别名(推荐)
import { ChatHeader } from '@/app/components/ChatHeader';2.3 package.json - 项目依赖
文件位置:package.json
核心依赖说明
{
"dependencies": {
"next": "16.1.1", // Next.js 框架
"react": "^19.2.0", // React UI 库
"react-dom": "^19.2.0", // React DOM 渲染器
"typescript": "^5.9.3", // TypeScript 编译器
"@langchain/langgraph": "^1.0.2", // LangGraph 状态图框架
"@langchain/google-genai": "^2.1.3", // Google AI 集成
"@supabase/supabase-js": "^2.89.0", // Supabase 客户端
"tailwindcss": "^4.1.17", // Tailwind CSS
"react-markdown": "^10.1.0", // Markdown 渲染
"uuid": "^13.0.0", // UUID 生成器
"zod": "^4.1.12" // 数据验证库
}
}npm scripts 说明
{
"scripts": {
"dev": "next dev", // 启动开发服务器
"build": "next build", // 构建生产版本
"start": "next start", // 启动生产服务器
"lint": "next lint", // 代码检查
"test": "vitest", // 运行测试
"pm2:start": "pm2 start ecosystem.config.js" // PM2 部署
}
}常用命令:
# 开发模式
pnpm dev
# 构建生产版本
pnpm build
# 启动生产服务器
pnpm start
# 代码检查
pnpm lint
# 运行测试
pnpm test3️⃣ 环境变量配置
3.1 环境变量文件
在项目根目录创建 .env 文件:
# Supabase 配置
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY=your-anon-key
# Google AI 配置
GOOGLE_API_KEY=your-google-api-key
GOOGLE_MODEL_NAME=gemini-3-pro-image-preview
# Tavily 搜索配置(DeepResearch 必需)
TAVILY_API_KEY=your-tavily-api-key3.2 环境变量命名规则
| 前缀 | 说明 |
|---|---|
NEXT_PUBLIC_ | 公开变量(可在浏览器访问) |
| 无前缀 | 私有变量(只能在服务器端访问) |
示例:
// 客户端可以访问
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
// 只能在服务器端访问(API Routes、Server Components)
const apiKey = process.env.GOOGLE_API_KEY;3.3 本项目使用的环境变量
| 变量名 | 是否公开 | 作用 |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL | ✅ 是 | Supabase 项目 URL |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY | ✅ 是 | Supabase 匿名密钥 |
GOOGLE_API_KEY | ❌ 否 | Google AI API 密钥 |
GOOGLE_MODEL_NAME | ❌ 否 | 默认 AI 模型名称 |
TAVILY_API_KEY | ❌ 否 | Tavily 搜索 API 密钥 |
4️⃣ 实战案例:配置文件使用
4.1 使用路径别名导入
在代码中使用 @/ 前缀简化导入路径:
// ✅ 推荐:使用路径别名
import { sessionService } from '@/app/services';
import { withAuth } from '@/app/middleware/auth';
import type { SessionType } from '@/app/database/sessions';
// ❌ 不推荐:使用相对路径
import { sessionService } from '../../../services/session.service';
import { withAuth } from '../../middleware/auth';查看实际使用:app/api/chat/sessions/route.ts
4.2 读取环境变量
在 API Routes 中使用环境变量:
// app/api/chat/route.ts
import { createClient } from '@supabase/supabase-js';
// 读取公开环境变量(客户端和服务端都可访问)
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY!;
// 创建 Supabase 客户端
const supabase = createClient(supabaseUrl, supabaseKey);4.3 使用 package.json 脚本
# 启动开发服务器
pnpm dev
# → 运行 next dev
# → 访问 http://localhost:3000
# 构建生产版本
pnpm build
# → 运行 next build
# → 生成 .next 目录
# 启动生产服务器
pnpm start
# → 运行 next start
# → 使用构建好的 .next 目录5️⃣ 本项目的分层架构
5.1 三层架构示意图
5.2 各层职责说明
| 层级 | 目录 | 职责 | 示例文件 |
|---|---|---|---|
| 表现层 | app/components/ | UI 渲染、用户交互 | ChatInput.tsx, MessageList.tsx |
| API 层 | app/api/ | HTTP 请求处理、认证 | route.ts |
| 服务层 | app/services/ | 业务逻辑、数据验证 | chat.service.ts |
| 数据层 | app/database/ | CRUD 操作、数据访问 | sessions.ts, artifacts.ts |
| 状态层 | app/hooks/ | 状态管理、逻辑封装 | useChatMessages.ts |
| 中间件 | app/middleware/ | 请求拦截、认证 | auth.ts |
5.3 架构原则(硬性规则)
根据项目文档 AGENTS.md
Routes (app/api/**/route.ts)
↓ calls
Services (app/services/*.service.ts)
↓ calls
Database (app/database/*.ts)绝对禁止:
- ❌ Route 直接调用 Database(跳过 Service 层)
- ❌ Service 层没有业务逻辑(直接透传)
- ❌ Database 层包含业务逻辑
推荐做法:
- ✅ Route 只处理 HTTP 请求/响应
- ✅ Service 包含验证和业务逻辑
- ✅ Database 是纯 CRUD 操作
6️⃣ 练习题
-
简答题:Next.js 的
app/目录与pages/目录有什么区别? -
代码题:根据文件系统路由规则,以下文件会生成什么 URL?
app/ ├── page.tsx ├── about/ │ └── page.tsx ├── product/ │ └── [id]/ │ └── page.tsx └── api/ └── users/ └── route.ts -
配置题:如何在
tsconfig.json中添加新的路径别名@components/,指向app/components/目录? -
分析题:查看本项目的 app/api/chat/sessions/route.ts,说明它如何使用路径别名和环境变量。
📚 参考资源
官方文档
本项目相关文件
✅ 总结
Next.js App Router 核心目录:
app/page.tsx- 首页app/layout.tsx- 全局布局app/api/- API Routesapp/components/- React 组件app/services/- 业务逻辑层app/database/- 数据访问层app/hooks/- 自定义 Hooks
核心配置文件:
next.config.ts- Next.js 框架配置tsconfig.json- TypeScript 配置(路径别名)package.json- 项目依赖和脚本.env- 环境变量
分层架构原则:
- Routes → Services → Database
- 职责清晰,避免直接跨层调用
下一步:阅读下一篇文章《路由系统基础》,深入了解 Next.js 的文件系统路由。
登录以继续阅读
解锁完整文档、代码示例及更多高级功能。