Skip to main content

部署

恭喜,现在是将应用部署到生产环境的时候了。

您可以使用 Vercel 部署托管的 Next.js, 或者自行托管在 Node.js 服务器上、Docker 镜像上,甚至是静态 HTML 文件上。 使用 next start 部署时,支持所有 Next.js 的功能。

生产构建

运行 next build 会生成您的应用程序的优化版本, 为生产环境生成基于页面的 HTML、CSS 和 JavaScript 文件。 JavaScript 会经过编译,使用 Next.js 编译器进行最小化,以实现最佳性能并支持所有现代浏览器。

Next.js 生成标准的部署输出,用于托管和自托管的 Next.js, 确保在这两种部署方法中都支持所有功能。 在下一个主要版本中,我们将把这个输出转换为我们的构建输出 API 规范。

使用 Vercel 托管的 Next.js

Vercel 是 Next.js 的创建者和维护者,为 Next.js 应用程序提供托管基础设施和开发者体验平台。

在 Vercel 上部署零配置,提供了额外的增强功能,包括全球范围的可伸缩性、可用性和性能。 然而,当自行托管时,所有 Next.js 的功能仍然得到支持。

了解更多关于在 Vercel 上使用 Next.js,或者尝试使用免费模板进行部署。

自托管

您可以以三种不同的方式自行托管 Next.js:

  1. 一个 Node.js 服务器
  2. 一个 Docker 容器
  3. 一个静态导出

Node.js 服务器

Next.js 可以部署到支持 Node.js 的任何托管提供者。 确保您的 package.json 包含 "build""start" 脚本:

{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}

然后,运行 npm run build 来构建您的应用程序。 最后,运行 npm run start 来启动 Node.js 服务器。该服务器支持所有 Next.js 的功能。

Docker 镜像

Next.js 可以部署到支持 Docker 容器的任何托管提供者。 当部署到容器编排器(例如 Kubernetes)或在任何云提供商的容器中运行时,可以使用这种方法。

  1. 在您的机器上安装 Docker
  2. 克隆我们的示例( 或多环境示例)。
  3. 构建您的容器:docker build -t nextjs-docker .
  4. 运行您的容器:docker run -p 3000:3000 nextjs-docker

通过 Docker 运行的 Next.js 支持所有 Next.js 的功能。

静态 HTML 导出

Next.js 启用了以静态站点或单页应用(SPA)的形式开始,然后选择升级以使用需要服务器的功能的选项。

由于 Next.js 支持这种静态导出, 因此它可以部署和托管在任何可以提供 HTML/CSS/JS 静态资源的 Web 服务器上, 包括 AWS S3、Nginx 或 Apache。

作为静态导出 运行不支持需要服务器的 Next.js 功能。 了解更多.

note

服务器组件 在静态导出中得到支持。

特性

图片优化

通过 next/image 进行的图片优化在使用 next start 部署时是零配置的。 如果您希望使用一个单独的服务来优化图像,可以配置一个图片加载器。

图片优化可以在静态导出中使用,通过在 next.config.js 中定义一个自定义图片加载器。 请注意,图像是在运行时而不是在构建时进行优化。

note
  • 当自行托管时,考虑在生产环境中安装 sharp 以获得更高性能的图像优化, 通过在项目目录中运行 npm install sharp。 在 Linux 平台上,可能需要额外的配置以防止过度使用内存。
  • 了解有关优化图像的缓存行为以及如何配置 TTL 的更多信息。
  • 如果愿意,也可以禁用图像优化并仍保留使用 next/image 的其他优势。例如,如果您自己单独优化图像。

中间件

在使用 next start 部署时,中间件是零配置的。由于它需要访问传入请求,因此在使用静态导出时不受支持。

中间件使用的是一个运行时,该运行时是所有可用 Node.js API 的子集,以确保低延迟,因为它可能在应用程序的每个路由或资源前运行。该运行时不需要在“边缘”运行,并且在单区域服务器中运行。在多个区域中运行中间件需要额外的配置和基础设施。

如果您想要添加需要所有 Node.js API 的逻辑(或使用外部包),您可能可以将此逻辑移动到作为服务器组件的布局中。例如,检查标头和重定向。您还可以通过 next.config.js 使用标头、Cookie 或查询参数重定向或重写。如果这不起作用,还可以使用自定义服务器。

环境变量

Next.js 可以支持构建时和运行时的环境变量。

默认情况下,环境变量仅在服务器上可用。 要将环境变量暴露给浏览器,必须以 NEXT_PUBLIC_ 为前缀。 但是,这些公共环境变量将在 next build 期间内联到 JavaScript 捆绑包中。

要读取运行时环境变量,建议使用 getServerSideProps 或逐渐采用 App Router。 通过 App Router,我们可以在动态渲染期间安全地在服务器上读取环境变量。 这允许您使用一个 Docker 镜像,可以在多个具有不同值的环境中推广使用。

import { unstable_noStore as noStore } from 'next/cache';

export default function Component() {
noStore();
// cookies(), headers(), and other dynamic functions
// will also opt into dynamic rendering, making
// this env variable is evaluated at runtime
const value = process.env.MY_VALUE
// ...
}
note
  • 您可以使用 register 函数在服务器启动时运行代码。
  • 我们不建议使用 runtimeConfig 选项,因为这在独立输出模式下不起作用。相反,我们建议逐渐采用 App Router。

缓存和 ISR

Next.js 可以缓存响应、生成的静态页面、构建输出和其他静态资产,如图像、字体和脚本。

通过缓存和重新验证页面(使用增量静态再生(ISR)或 App Router 中的新功能)使用相同的共享缓存。 默认情况下,此缓存存储在 Next.js 服务器上的文件系统(磁盘上)。 这在使用 Pages 和 App Router 自行托管时会自动工作。

如果要将缓存的页面和数据持久保存到耐用存储, 或者共享缓存跨多个容器或实例的 Next.js 应用程序, 可以配置 Next.js 缓存位置。

自动缓存

  • Next.js 设置了 Cache-Control 标头为 public, max-age=31536000, immutable,用于真正的不可变资产。它无法被覆盖。这些不可变文件在文件名中包含 SHA 散列,因此可以安全地无限期缓存。例如,静态图像导入。您可以配置图像的 TTL。
  • 增量静态再生(ISR)将 Cache-Control 标头设置为 s-maxage: <getStaticProps 中的重新验证时间>, stale-while-revalidate。此重新验证时间在 getStaticProps 函数中以秒为单位定义。如果设置 revalidate: false,它将默认为一年的缓存持续时间。
  • 动态渲染的页面将 Cache-Control 标头设置为 private, no-cache, no-store, max-age=0, must-revalidate,以防止缓存用户特定数据。这适用于 App Router 和 Pages Router。这也包括 Draft Mode。

静态资产

如果要在不同的域或 CDN 上托管静态资产,可以使用 next.config.js 中的 assetPrefix 配置。 Next.js 在检索 JavaScript 或 CSS 文件时将使用此资产前缀。 将资产分离到不同的域会导致额外的时间用于 DNS 和 TLS 解析。

了解有关 assetPrefix 的更多信息。

配置缓存

默认情况下,生成的缓存资产将存储在内存中(默认为50MB)和磁盘上。 如果您使用类似 Kubernetes 的容器编排平台托管 Next.js,每个 pod 将有一个缓存的副本。 为了防止因为缓存默认情况下在 pod 之间不共享而显示陈旧数据, 您可以配置 Next.js 缓存以提供缓存处理程序并禁用内存中的缓存。

要在自行托管时配置 ISR/Data 缓存位置,您可以在您的 next.config.js 文件中配置一个自定义处理程序:

next.config.js
module.exports = {
experimental: {
incrementalCacheHandlerPath: require.resolve('./cache-handler.js'),
isrMemoryCacheSize: 0, // 禁用默认的内存中缓存
},
}

然后,在您项目的根目录中创建 cache-handler.js,例如:

cache-handler.js
const cache = new Map()

module.exports = class CacheHandler {
constructor(options) {
this.options = options
}

async get(key) {
// 这可以存储在任何地方,比如耐用存储
return cache.get(key)
}

async set(key, data, ctx) {
// 这可以存储在任何地方,比如耐用存储
cache.set(key, {
value: data,
lastModified: Date.now(),
tags: ctx.tags,
})
}

async revalidateTag(tag) {
// 遍历缓存中的所有条目
for (let [key, value] of cache) {
// 如果值的标签包含指定的标签,则删除此条目
if (value.tags.includes(tag)) {
cache.delete(key)
}
}
}
}

使用自定义缓存处理程序将使您能够确保在托管 Next.js 应用程序的所有 pod 中保持一致性。 例如,您可以将缓存的值保存在任何地方,比如 Redis 或 AWS S3。

note
  • revalidatePath 是在缓存标签之上的方便层。调用 revalidatePath 将使用提供页面的特殊默认标签调用 revalidateTag 函数。

构建缓存

Next.js 在 next build 期间生成一个 ID 以标识正在提供的应用程序版本。 应该使用相同的构建并启动多个容器。

如果您正在为环境的每个阶段重新构建,您将需要生成一个一致的构建 ID 以在容器之间使用。 可以在 next.config.js 中使用 generateBuildId 命令:

next.config.js
module.exports = {
generateBuildId: async () => {
// 这可以是任何东西,使用最新的 git 哈希
return process.env.GIT_HASH
},
}

版本偏差

Next.js 将自动减轻大多数版本偏差的情况,并在检测到时自动重新加载应用程序以检索新的资产。 例如,如果构建 ID 不匹配,页面之间的转换将执行硬导航而不是使用预取的值。

当应用程序重新加载时,如果其设计不是在页面导航之间持久存在状态,则可能会丢失应用程序状态。 例如,使用 URL 状态或本地存储将在页面刷新后保留状态。 但是,像 useState 这样的组件状态将在这样的导航中丢失。

Vercel 为 Next.js 应用程序提供了额外的偏差保护,以确保来自先前构建的资产和函数在新构建部署时仍然可用。