Next.js第二课 - 项目结构详解 - 优栈

上节我们搭建好了 Next.js 开发环境,本节就来详细了解一下 Next.js 的项目结构。很多初学者刚打开项目时会看到一堆文件和文件夹,不知道每个都是干什么的。别担心,本节会带你理清这些目录和文件的用途,让你对项目结构有一个清晰的认识。

项目结构概览

bash 复制代码
my-nextjs-app/
├── app/                          # App Router(主要工作目录)
│   ├── (auth)/                   # 路由组(不影响 URL)
│   │   ├── login/
│   │   │   └── page.tsx
│   │   └── register/
│   │       └── page.tsx
│   ├── api/                      # API 路由
│   │   └── users/
│   │       └── route.ts
│   ├── blog/                     # 应用路由
│   │   ├── [slug]/              # 动态路由
│   │   │   └── page.tsx
│   │   └── page.tsx
│   ├── layout.tsx               # 根布局
│   ├── page.tsx                 # 首页
│   ├── loading.tsx              # 加载状态
│   ├── error.tsx                # 错误处理
│   ├── not-found.tsx            # 404 页面
│   └── globals.css              # 全局样式
├── components/                   # 共享组件
│   ├── ui/                      # UI 基础组件
│   │   ├── Button.tsx
│   │   ├── Input.tsx
│   │   └── Card.tsx
│   └── layout/                  # 布局组件
│       ├── Header.tsx
│       └── Footer.tsx
├── lib/                         # 工具函数
│   ├── utils.ts
│   ├── api.ts
│   └── constants.ts
├── hooks/                       # 自定义 Hooks
│   ├── useAuth.ts
│   └── useData.ts
├── types/                       # TypeScript 类型
│   └── index.ts
├── public/                      # 静态资源
│   ├── images/
│   ├── fonts/
│   └── favicon.ico
├── styles/                      # 样式文件(可选)
│   └── globals.css
├── .env.local                   # 环境变量
├── .eslintrc.json              # ESLint 配置
├── .gitignore                  # Git 忽略文件
├── next.config.js              # Next.js 配置
├── package.json                # 项目配置
├── tsconfig.json               # TypeScript 配置
└── README.md                   # 项目说明

核心目录详解

1. app/ 目录 - App Router

app/ 目录是 Next.js 13+ 推荐的新路由系统,基于 React Server Components 构建。这是你工作中最常打交道的目录,绝大部分页面和路由都会放在这里。

特殊文件

文件 用途 必需
layout.tsx 定义布局和 UI 可选
page.tsx 定义路由的独特 UI 必需(可访问路由)
loading.tsx 加载时的 UI 替换 可选
error.tsx 错误边界 UI 可选
not-found.tsx 404 页面 可选
route.ts API 端点 API 路由必需

示例结构

bash 复制代码
app/
├── (marketing)/              # 路由组
│   ├── about/
│   │   └── page.tsx         # /about
│   ├── layout.tsx           # 营销页面共享布局
│   └── page.tsx             # /
├── (shop)/                   # 另一个路由组
│   ├── account/
│   │   └── page.tsx         # /account
│   └── layout.tsx           # 商店页面共享布局
├── products/
│   ├── [id]/                # 动态段
│   │   └── page.tsx         # /products/123
│   └── page.tsx             # /products
├── api/
│   └── users/
│       └── route.ts         # /api/users (API)
├── layout.tsx               # 根布局(所有页面共享)
└── page.tsx                 # 首页

2. components/ 目录

这里存放可复用的 React 组件。当你发现一段 UI 代码在多个页面重复出现时,就可以把它抽取成一个组件放到这里。随着项目变大,良好的组件组织会让代码更容易维护。

bash 复制代码
components/
├── ui/                       # 基础 UI 组件
│   ├── Button.tsx
│   ├── Input.tsx
│   ├── Modal.tsx
│   └── Table.tsx
├── layout/                   # 布局组件
│   ├── Header.tsx
│   ├── Footer.tsx
│   ├── Sidebar.tsx
│   └── Navigation.tsx
├── features/                 # 功能组件
│   ├── UserProfile.tsx
│   ├── ProductCard.tsx
│   └── CommentList.tsx
└── forms/                    # 表单组件
    ├── LoginForm.tsx
    └── ContactForm.tsx

组件示例

bash 复制代码
// components/ui/Button.tsx
interface ButtonProps {
  children: React.ReactNode
  onClick?: () => void
  variant?: 'primary' | 'secondary'
}

export function Button({ children, onClick, variant = 'primary' }: ButtonProps) {
  return (
    <button
      onClick={onClick}
      className={`px-4 py-2 rounded ${
        variant === 'primary'
          ? 'bg-blue-500 text-white'
          : 'bg-gray-200 text-gray-800'
      }`}
    >
      {children}
    </button>
  )
}

3. lib/ 目录

这里存放工具函数、API 客户端、常量等辅助代码。把不属于任何特定业务逻辑的通用代码放在这里是个好习惯。

bash 复制代码
lib/
├── utils/                    # 工具函数
│   ├── format.ts            # 格式化函数
│   ├── validation.ts        # 验证函数
│   └── helpers.ts           # 辅助函数
├── api/                      # API 客户端
│   ├── client.ts
│   ├── users.ts
│   └── products.ts
├── db/                       # 数据库相关
│   ├── connect.ts
│   └── queries.ts
└── constants.ts              # 常量定义

工具函数示例

bash 复制代码
// lib/utils/format.ts

export function formatDate(date: Date): string {
  return new Intl.DateTimeFormat('zh-CN', {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
  }).format(date)
}

export function formatCurrency(amount: number): string {
  return new Intl.NumberFormat('zh-CN', {
    style: 'currency',
    currency: 'CNY',
  }).format(amount)
}

4. hooks/ 目录

存放自定义 React Hooks。如果你有一些状态逻辑需要在多个组件中复用,就可以封装成自定义 Hook 放在这里。

bash 复制代码
hooks/
├── useAuth.ts                # 认证相关
├── useData.ts                # 数据获取
├── useForm.ts                # 表单处理
└── useLocalStorage.ts        # 本地存储

Hook 示例

bash 复制代码
// hooks/useAuth.ts
'use client'

import { useState, useEffect } from 'react'

export function useAuth() {
  const [isAuthenticated, setIsAuthenticated] = useState(false)
  const [user, setUser] = useState(null)

  useEffect(() => {
    // 检查认证状态
    const token = localStorage.getItem('token')
    setIsAuthenticated(!!token)
  }, [])

  return { isAuthenticated, user }
}

5. public/ 目录

这里存放静态资源,比如图片、字体、favicon 等。放在 public 目录下的文件可以直接通过 URL 访问,不需要 import。

bash 复制代码
public/
├── images/
│   ├── logo.png
│   └── banner.jpg
├── fonts/
│   └── custom-font.woff2
├── favicon.ico
└── robots.txt

使用方式

bash 复制代码
// 在组件中引用
<Image src="/images/logo.png" alt="Logo" width={200} height={100} />

6. 根配置文件

next.config.js

bash 复制代码
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,

  // 图片优化配置
  images: {
    domains: ['example.com'],
    formats: ['image/avif', 'image/webp'],
  },

  // 环境变量
  env: {
    CUSTOM_KEY: process.env.CUSTOM_KEY,
  },

  // 重定向
  async redirects() {
    return [
      {
        source: '/old-path',
        destination: '/new-path',
        permanent: true,
      },
    ]
  },
}

module.exports = nextConfig

tsconfig.json

bash 复制代码
{
  "compilerOptions": {
    "target": "ES2017",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

路由组织最佳实践

1. 使用路由组

路由组 (group-name) 是 Next.js 的一个很有用的特性,它不会影响 URL 路径,但可以帮助你更好地组织代码和共享布局。比如你想把某些页面放在一起管理,但又不想改变 URL 结构,就可以用路由组。

bash 复制代码
app/
├── (marketing)/              # /about, /contact
│   ├── about/
│   │   └── page.tsx
│   ├── contact/
│   │   └── page.tsx
│   └── layout.tsx           # 营销页面共享布局
├── (dashboard)/              # /dashboard, /settings
│   ├── dashboard/
│   │   └── page.tsx
│   ├── settings/
│   │   └── page.tsx
│   └── layout.tsx           # 需要认证的布局
└── page.tsx                 # 首页

2. 动态路由

动态路由在实际开发中非常常见,比如博客文章页、用户详情页等。使用方括号 [param] 就可以创建动态路由段,Next.js 会自动匹配并解析参数。

bash 复制代码
app/
├── blog/
│   ├── [slug]/              # /blog/hello-world
│   │   └── page.tsx
│   └── page.tsx             # /blog
├── products/
│   ├── [category]/          # /products/electronics
│   │   └── page.tsx
│   └── page.tsx             # /products
└── users/
    └── [id]/                # /users/123
        ├── [action]/        # /users/123/edit
        │   └── page.tsx
        └── page.tsx         # /users/123

3. 并行和拦截路由

并行路由和拦截路由是 Next.js 的高级特性,可以实现一些复杂的交互效果,比如模态框、并行加载多个页面等。这些特性在实际项目中非常有用,但理解起来可能需要一点时间。

bash 复制代码
app/
├── @dashboard/               # 并行路由槽
│   └── page.tsx
├── (.)modal/                 # 拦截路由
│   └── photo/[id]/page.tsx
├── dashboard/
│   └── page.tsx
└── layout.tsx

文件命名约定

路由相关

模式 说明 示例 URL
folder/page.tsx 标准路由 /folder
folder/[slug]/page.tsx 动态路由 /folder/value
folder/[[...slug]]/page.tsx 捕获所有路由 /folder/a/b/c
(group)/page.tsx 路由组 /page
folder/(.)modal/... 拦截路由 -

特殊文件

文件 说明
_filename.tsx 私有文件,不创建路由
filename.server.tsx 仅在服务器运行
filename.client.tsx 仅在客户端运行

代码组织建议

1. 按功能组织

按功能组织是一种常见的项目结构方式,把相关的功能放在一起。这种方式适合中小型项目,代码结构清晰易懂。

bash 复制代码
app/
├── (auth)/
│   ├── login/
│   ├── register/
│   └── forgot-password/
├── (dashboard)/
│   ├── overview/
│   ├── analytics/
│   └── settings/
└── (public)/
    ├── about/
    ├── contact/
    └── pricing/

2. 按层级组织

按层级组织适合大型项目,比如有 API 版本管理、多级管理后台等场景。这种方式可以让结构更有层次感。

bash 复制代码
app/
├── api/
│   ├── v1/
│   │   ├── users/
│   │   └── posts/
│   └── v2/
│       └── users/
└── admin/
    └── users/
        ├── [id]/
        └── new/

3. 组件分层

组件分层是一种借鉴原子设计的组织方式,把组件按照复杂度分成原子、分子、组织、模板等层级。这种方式适合 UI 组件库或者设计系统比较完善的项目。

bash 复制代码
components/
├── atoms/                    # 最小单元
│   ├── Button.tsx
│   └── Input.tsx
├── molecules/                # 组合原子
│   ├── SearchBar.tsx
│   └── FormField.tsx
├── organisms/                # 复杂组件
│   ├── Header.tsx
│   └── ProductCard.tsx
└── templates/                # 页面模板
    └── BlogLayout.tsx

环境变量

环境变量用来存储一些敏感信息或者配置,比如数据库连接字符串、API 密钥等。创建 .env.local 文件来存放这些信息,记得把这个文件加到 .gitignore 里,不要提交到代码仓库。

bash 复制代码
# 数据库
DATABASE_URL=postgresql://...

# API 密钥
API_KEY=your_api_key
API_SECRET=your_api_secret

# 应用配置
NEXT_PUBLIC_APP_URL=http://localhost:3000

访问方式:

bash 复制代码
// 服务器端
const dbUrl = process.env.DATABASE_URL

// 客户端(必须以 NEXT_PUBLIC_ 开头)
const appUrl = process.env.NEXT_PUBLIC_APP_URL

总结

本节我们详细了解了 Next.js 的项目结构,包括各个目录的用途、路由组织方式、以及一些最佳实践。掌握项目结构是学好 Next.js 的基础,建议你多花点时间理解这些内容。

如果你对本节内容有任何疑问,欢迎在评论区提出来,我们一起学习讨论。

原文链接:https://blog.uuhb.cn/archives/Next-js-02.html

相关推荐
skywalkzf2 小时前
全志 V853 开发:lunch 不显示项目列表问题排查与解决
前端·chrome
踩着两条虫2 小时前
VTJ.PRO 在线应用开发平台的项目模板(Web、H5、UniApp)
前端·低代码·ai编程
云原生指北2 小时前
测试文章标题 - Omnipub 自动发布测试
前端
无责任此方_修行中2 小时前
"JavaScript"这个名字,到底属于谁?一场价值74亿美元的法律战争
前端·javascript·程序员
CharlesY2 小时前
网页排版与编码的隐形神器:HTML字符实体从入门到精通
前端
我命由我123452 小时前
React - useEffect、useRef、Fragment
开发语言·前端·javascript·react.js·前端框架·ecmascript·js
云原生指北2 小时前
测试文章 - 摘要自定义填充验证
前端
她的男孩2 小时前
ForgeAdmin 更新:新增第三方登录认证 + 数据字段脱敏两大企业级特性
前端·后端
KevinCyao2 小时前
Ruby短信营销接口示例代码:Ruby开发环境下营销短信API接口的集成与Demo演示
开发语言·前端·ruby