NextJs的目录结构说明
Table of Contents
以下是一个典型的 Next.js 项目(基于最新版本,使用 App Router)的目录结构及其核心文件的含义和使用说明:
项目根目录
my-next-app/
├── app/ # 核心路由和页面(App Router)
│ ├── layout.tsx # 全局布局组件
│ ├── page.tsx # 首页(对应路由 `/`)
│ ├── (auth)/ # 路由组(分组路由,不反映在 URL 中)
│ ├── blog/ # 嵌套路由 `/blog`
│ │ ├── page.tsx # `/blog` 页面
│ │ └── [slug]/ # 动态路由(如 `/blog/hello-world`)
│ │ └── page.tsx
│ └── api/ # API 路由(可选,或使用单独的 `pages/api`)
│ └── route.ts
├── public/ # 静态资源(图片、字体等,直接通过 `/` 访问)
├── components/ # 可复用的 React 组件
├── lib/ # 工具函数、第三方库封装
├── styles/ # 全局 CSS 或 SCSS 文件
├── .env.local # 环境变量(仅在本地生效)
├── next.config.js # Next.js 自定义配置
├── package.json # 项目依赖和脚本
└── middleware.ts # 中间件(处理请求前执行)
核心文件/目录详解
1. app/
目录(App Router)
-
核心功能:存放页面、布局和路由逻辑。
-
关键文件:
-
layout.tsx
- 作用:定义全局布局(如导航栏、页脚),包裹所有子页面。
- 示例:
export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body>{children}</body> </html> ); }
-
page.tsx
- 作用:每个路由的页面组件,文件名必须为
page.tsx
。 - 示例(首页
/
):export default function Home() { return <h1>Welcome to Next.js!</h1>; }
- 作用:每个路由的页面组件,文件名必须为
-
route.ts
- 作用:定义 API 路由(替代旧版
pages/api
)。 - 示例(
GET /api/users
):export async function GET() { return Response.json({ users: [] }); }
- 作用:定义 API 路由(替代旧版
-
-
动态路由:
使用[param]
文件夹名(如app/blog/[slug]/page.tsx
)捕获动态参数,通过params
获取:export default function BlogPage({ params }: { params: { slug: string } }) { return <div>Post: {params.slug}</div>; }
2. public/
目录
- 作用:存放静态资源,可通过 URL 直接访问(如
/logo.png
对应public/logo.png
)。 - 典型文件:
favicon.ico
:网站图标。robots.txt
:搜索引擎爬虫规则。
3. components/
目录
- 作用:存放可复用的 React 组件(如
Button.tsx
、Header.tsx
)。 - 最佳实践:按功能或模块划分子目录(如
components/ui/
存放通用 UI 组件)。
4. next.config.js
- 作用:自定义 Next.js 配置(如重定向、图像优化、环境变量等)。
- 示例:
module.exports = { images: { domains: ['example.com'], // 允许加载的图片域名 }, redirects: async () => [ { source: '/old', destination: '/new', permanent: true }, ], };
5. middleware.ts
- 作用:在请求处理前执行代码(如身份验证、重定向)。
- 示例(重定向未登录用户):
import { NextResponse } from 'next/server'; export function middleware(request) { if (!request.cookies.get('token')) { return NextResponse.redirect(new URL('/login', request.url)); } return NextResponse.next(); }
6. 环境变量文件
.env.local
:本地环境变量(通过process.env.VAR_NAME
访问)。- 命名规则:
NEXT_PUBLIC_
前缀的变量会在客户端暴露(如NEXT_PUBLIC_API_URL
)。- 其他变量仅限服务端使用。
其他重要文件
styles/globals.css
:全局 CSS 样式(在layout.tsx
中导入)。tailwind.config.js
:Tailwind CSS 配置(如果使用)。tsconfig.json
:TypeScript 配置(自动生成,可自定义路径别名)。
版本差异说明
- Pages Router(旧版):使用
pages/
目录,动态路由通过文件名(如pages/blog/[slug].js
)实现。 - App Router(推荐):更灵活的路由结构,支持嵌套布局和 React Server Components。
通过这种结构化的设计,Next.js 项目能够高效管理路由、组件和静态资源,同时保持代码的可维护性。
补充多语言项目目录
在 Next.js 项目中实现多语言(国际化,i18n)时,通常会结合 路由前缀(如 /en/...
或 /zh-CN/...
)和 翻译文件 来实现。以下是基于 App Router 的典型多语言项目目录结构及关键文件说明:
目录结构示例
my-next-app/
├── app/
│ ├── [lang]/ # 动态语言路由(核心变化!)
│ │ ├── layout.tsx # 语言层级的布局(可在此加载翻译)
│ │ ├── page.tsx # 首页(如 `/en` 或 `/zh-CN`)
│ │ ├── blog/ # 嵌套路由 `/en/blog` 或 `/zh-CN/blog`
│ │ │ └── page.tsx
│ │ └── (common)/ # 无需语言前缀的路由组(如登录页)
│ ├── (root)/ # 无语言前缀的路由组(可选,如重定向逻辑)
│ │ └── page.tsx # 自动重定向到默认语言
├── public/
├── locales/ # 存放多语言翻译文件(核心新增!)
│ ├── en/
│ │ ├── common.json # 通用翻译
│ │ └── blog.json
│ └── zh-CN/
│ ├── common.json
│ └── blog.json
├── middleware.ts # 处理语言检测和重定向
└── ...
关键变化说明
1. 动态语言路由 (app/[lang]/
)
- 作用:通过 URL 路径前缀区分语言(如
/en/blog
或/zh-CN/blog
)。 - 实现方式:
- 将整个应用包裹在
app/[lang]/
目录下。 - 通过
params.lang
获取当前语言:// app/[lang]/layout.tsx export default function Layout({ params, children }) { const lang = params.lang; // 'en' 或 'zh-CN' return <>{children}</>; }
- 将整个应用包裹在
2. 语言翻译文件 (locales/
)
- 作用:按语言和模块组织翻译内容。
- 典型结构:
locales/ ├── en/ │ ├── common.json // 通用文本 │ └── blog.json // 博客相关文本 └── zh-CN/ ├── common.json └── blog.json
- 示例内容 (
locales/en/common.json
):{ "header": { "home": "Home", "blog": "Blog" } }
3. 中间件 (middleware.ts
)
-
作用:自动检测用户语言并重定向到对应路由(基于浏览器设置或 Cookie)。
-
示例代码:
import { NextRequest, NextResponse } from 'next/server'; const locales = ['en', 'zh-CN']; const defaultLocale = 'en'; export function middleware(request: NextRequest) { // 1. 检查 URL 中是否已包含语言 const pathname = request.nextUrl.pathname; if (pathname.startsWith(`/${defaultLocale}/`)) { return NextResponse.redirect(new URL(pathname.replace(/^\/en/, ''), request.url)); } // 2. 从 Cookie 或浏览器语言获取偏好 const langCookie = request.cookies.get('lang'); const acceptLanguage = request.headers.get('accept-language')?.split(',')[0]; const preferredLang = langCookie || acceptLanguage || defaultLocale; // 3. 重定向到匹配的语言路由 if (!locales.some(locale => pathname.startsWith(`/${locale}`))) { return NextResponse.redirect(new URL(`/${preferredLang}${pathname}`, request.url)); } return NextResponse.next(); }
4. 语言切换组件
-
作用:允许用户手动切换语言(需更新 URL 和 Cookie)。
-
示例实现:
// components/LanguageSwitcher.tsx import Link from 'next/link'; import { usePathname } from 'next/navigation'; export default function LanguageSwitcher() { const pathname = usePathname(); const currentLang = pathname.split('/')[1]; const switchLanguage = (lang: string) => { // 替换当前路径中的语言部分 const newPath = pathname.replace(/^\/[a-z-]+/, `/${lang}`); return newPath; }; return ( <div> <Link href={switchLanguage('en')} locale={false}>English</Link> <Link href={switchLanguage('zh-CN')} locale={false}>中文</Link> </div> ); }
使用 i18n 库(推荐)
虽然可以手动实现,但使用专门的库(如 next-intl 或 next-i18next)可简化流程:
使用 next-intl
的调整:
-
配置 (
next.config.js
):const withNextIntl = require('next-intl/plugin')(); module.exports = withNextIntl();
-
翻译加载 (
app/[locale]/layout.tsx
):import { useTranslations } from 'next-intl'; export default function RootLayout({ children, params: { locale } }) { const t = useTranslations('common'); return ( <html lang={locale}> <body> <nav>{t('header.home')}</nav> {children} </body> </html> ); }
注意事项
-
SEO 优化:
- 使用
<link rel="alternate" hreflang="x" href="...">
标签声明多语言页面。 - 在
generateMetadata
中动态生成语言相关的元数据。
- 使用
-
静态生成:
- 使用
generateStaticParams
预生成所有语言版本:// app/[lang]/page.tsx export async function generateStaticParams() { return [{ lang: 'en' }, { lang: 'zh-CN' }]; }
- 使用
-
默认语言处理:
- 通过中间件将根路径(
/
)重定向到默认语言(如/en
)。
- 通过中间件将根路径(
通过这种结构,你可以实现:
- 清晰的 URL 语言标识(如
/en/blog
) - 按模块组织的翻译文件
- 自动语言检测与切换
- 与 Next.js 特性(SSG、ISR)无缝集成
明天了解一下 NextJs 的后端目录结构