项目结构与组织

本页全面介绍了 Next.js 中所有文件夹与文件约定,并提供项目组织建议。

文件夹与文件约定

顶级文件夹

顶级文件夹用于组织应用程序代码和静态资源。

路由段与路径段对应关系
app应用路由 (App Router)
pages页面路由 (Pages Router)
public静态资源文件
src可选的应用程序源代码文件夹

顶级文件

顶级文件用于配置应用程序、管理依赖项、运行中间件、集成监控工具以及定义环境变量。

Next.js 相关
next.config.jsNext.js 配置文件
package.json项目依赖项与脚本
instrumentation.tsOpenTelemetry 与性能监控文件
middleware.tsNext.js 请求中间件
.env环境变量
.env.local本地环境变量
.env.production生产环境变量
.env.development开发环境变量
.eslintrc.jsonESLint 配置文件
.gitignoreGit 忽略文件列表
next-env.d.tsNext.js 的 TypeScript 声明文件
tsconfig.jsonTypeScript 配置文件
jsconfig.jsonJavaScript 配置文件

路由文件

layout.js .jsx .tsx布局组件
page.js .jsx .tsx页面组件
loading.js .jsx .tsx加载状态 UI
not-found.js .jsx .tsx404 页面
error.js .jsx .tsx错误边界 UI
global-error.js .jsx .tsx全局错误边界
route.js .tsAPI 端点
template.js .jsx .tsx可重渲染的布局
default.js .jsx .tsx并行路由的备用页面

嵌套路由

folder路由段
folder/folder嵌套路由段

动态路由

[folder]动态路由段
[...folder]全捕获路由段
[[...folder]]可选全捕获路由段

路由组与私有文件夹

(folder)不影响实际路由的分组
_folder将文件夹及其子路由段排除在路由系统外

并行路由与拦截路由

@folder命名插槽
(.)folder拦截同级路由
(..)folder拦截上一级路由
(..)(..)folder拦截上两级路由
(...)folder从根路由拦截

元数据文件约定

应用图标

favicon.ico网站图标文件
icon.ico .jpg .jpeg .png .svg应用图标文件
icon.js .ts .tsx通过代码生成的应用图标
apple-icon.jpg .jpeg, .pngApple 应用图标文件
apple-icon.js .ts .tsx通过代码生成的 Apple 图标

Open Graph 与 Twitter 图片

opengraph-image.jpg .jpeg .png .gifOpen Graph 图片文件
opengraph-image.js .ts .tsx通过代码生成的 Open Graph 图片
twitter-image.jpg .jpeg .png .gifTwitter 图片文件
twitter-image.js .ts .tsx通过代码生成的 Twitter 图片

SEO 优化

sitemap.xml站点地图文件
sitemap.js .ts通过代码生成的站点地图
robots.txt爬虫协议文件
robots.js .ts通过代码生成的爬虫协议

组织项目结构

Next.js 对项目文件组织方式不做强制要求,但提供了多种功能来帮助您管理项目。

组件层级

特殊文件中定义的组件会按照特定层级渲染:

  1. layout.js
  2. template.js
  3. error.js (React 错误边界)
  4. loading.js (React Suspense 边界)
  5. not-found.js (React 错误边界)
  6. page.js 或嵌套的 layout.js
文件约定的组件层级结构

在嵌套路由中,组件会递归渲染,这意味着子路由段的组件会嵌套在其父路由段组件内部

嵌套文件约定的组件层级

文件同置 (Colocation)

app 目录中,嵌套文件夹定义了路由结构。每个文件夹代表一个路由片段,对应 URL 路径中的相应片段。

但需要注意的是,尽管路由结构通过文件夹定义,只有当路由片段中添加了 page.jsroute.js 文件时,该路由才会对外可访问

示意图展示如何通过添加 page.js 或 route.js 文件使路由对外可访问

即使路由对外可访问后,也仅有 page.jsroute.js 返回的内容会被发送到客户端。

示意图展示 page.js 和 route.js 文件如何使路由对外可访问

这意味着项目文件可以安全地同置app 目录的路由片段中,而不会意外成为可访问路由。

示意图展示同置的项目文件即使所在片段包含 page.js 或 route.js 也不会成为可访问路由

须知:虽然你可以将项目文件同置在 app 目录中,但并非必须这样做。如果愿意,你也可以将它们保留在 app 目录外

私有文件夹 (Private folders)

通过给文件夹添加下划线前缀可以创建私有文件夹:_folderName

这表示该文件夹是私有实现细节,路由系统不应考虑它,从而将该文件夹及其所有子文件夹排除在路由之外。

使用私有文件夹的示例文件夹结构

由于 app 目录中的文件默认可以安全同置,私有文件夹并非同置所必需。但它们可用于:

  • 将 UI 逻辑与路由逻辑分离。
  • 在项目和 Next.js 生态系统中一致组织内部文件。
  • 在代码编辑器中排序和分组文件。
  • 避免与未来 Next.js 文件约定的潜在命名冲突。

须知

  • 虽然不是框架约定,你也可以考虑使用相同的下划线模式标记私有文件夹外的文件为“私有”。
  • 可以通过给文件夹名添加 %5F(下划线的 URL 编码形式)来创建以下划线开头的 URL 片段:%5FfolderName
  • 如果不使用私有文件夹,了解 Next.js 的特殊文件约定有助于避免意外的命名冲突。

路由组 (Route groups)

通过将文件夹包裹在括号中可以创建路由组:(folderName)

这表示该文件夹仅用于组织目的,不应包含在路由的 URL 路径中。

使用路由组的示例文件夹结构

路由组适用于:

src 文件夹

Next.js 支持将应用代码(包括 app)存储在可选的 src 文件夹中。这可以将应用代码与主要位于项目根目录的配置文件分开。

包含 `src` 文件夹的示例文件夹结构

示例

以下部分列出了常见策略的概要。最简单的建议是选择适合你和团队的策略,并在项目中保持一致。

须知:在下面的示例中,我们使用 componentslib 文件夹作为通用占位符,它们的命名没有特殊的框架意义,你的项目可能会使用其他文件夹如 uiutilshooksstyles 等。

将项目文件存储在 app

此策略将所有应用代码存储在项目根目录的共享文件夹中,并保持 app 目录纯粹用于路由目的。

项目文件存储在 app 外的示例文件夹结构

将项目文件存储在 app 内的顶层文件夹中

此策略将所有应用代码存储在 app 目录根目录的共享文件夹中。

项目文件存储在 app 内的示例文件夹结构

按功能或路由拆分项目文件

此策略将全局共享的应用代码存储在 app 根目录中,并将更具体的应用代码拆分到使用它们的路由片段中。

按功能或路由拆分项目文件的示例文件夹结构

组织路由而不影响 URL 路径

要组织路由而不影响 URL,可以创建一个组来将相关路由保持在一起。括号中的文件夹将从 URL 中省略(例如 (marketing)(shop))。

使用路由组组织路由

尽管 (marketing)(shop) 中的路由共享相同的 URL 层次结构,但你可以通过在其文件夹中添加 layout.js 文件为每个组创建不同的布局。

具有多个布局的路由组

将特定片段加入布局

要将特定路由加入布局,可以创建一个新的路由组(例如 (shop)),并将共享相同布局的路由移动到该组中(例如 accountcart)。组外的路由不会共享该布局(例如 checkout)。

具有选择加入布局的路由组

为特定路由选择加载骨架

要通过 loading.js 文件将加载骨架应用到特定路由,可以创建一个新的路由组(例如 /(overview)),然后将 loading.tsx 移动到该路由组中。

文件夹结构展示路由组中的 loading.tsx 和 page.tsx

现在,loading.tsx 文件将仅应用于你的 dashboard → overview 页面,而不是所有 dashboard 页面,且不影响 URL 路径结构。

创建多个根布局

要创建多个根布局,可以移除顶层的 layout.js 文件,并在每个路由组中添加一个 layout.js 文件。这对于将应用划分为具有完全不同 UI 或体验的部分非常有用。每个根布局都需要添加 <html><body> 标签。

具有多个根布局的路由组

在上面的示例中,(marketing)(shop) 都有自己的根布局。