Menu

部署

恭喜你,是时候部署到生产环境了。

你可以选择 使用 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:

Node.js 服务器

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

package.json
{
  "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 功能。了解更多

值得注意的是

功能

图像优化

通过 next/image 实现的 图像优化 在使用 next start 部署时可以零配置自托管。如果你更喜欢使用单独的服务来优化图像,你可以 配置图像加载器

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

值得注意的是

  • 在基于 glibc 的 Linux 系统上,图像优化可能需要 额外配置 以防止过度内存使用。
  • 了解更多关于 优化图像的缓存行为 以及如何配置 TTL。
  • 如果你更愿意,你也可以 禁用图像优化 并仍然保留使用 next/image 的其他好处。例如,如果你正在单独优化图像。

中间件

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

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

如果你想添加需要所有 Node.js API 的逻辑 (或使用外部包),你可能可以将这个逻辑移动到 布局 中作为 服务器组件。例如,检查 头部信息重定向。你还可以使用头部信息、cookie 或查询参数通过 next.config.js 进行 重定向重写。如果这些方法都不适用,你还可以使用 自定义服务器

环境变量

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() 和其他动态函数
  // 也会选择动态渲染,使得
  // 这个环境变量在运行时被评估
  const value = process.env.MY_VALUE
  ...
}

值得注意的是

  • 你可以使用 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: <revalidate in getStaticProps>, stale-while-revalidate。这个重新验证时间在你的 getStaticProps 函数 中以秒为单位定义。如果你设置 revalidate: false,它将默认为一年的缓存持续时间。
  • 动态渲染的页面设置 Cache-Control 头为 private, no-cache, no-store, max-age=0, must-revalidate,以防止用户特定数据被缓存。这适用于 App Router 和 Pages Router。这也包括 草稿模式

静态资源

如果你想在不同的域名或 CDN 上托管静态资源,你可以在 next.config.js 中使用 assetPrefix 配置。Next.js 在检索 JavaScript 或 CSS 文件时会使用这个资源前缀。将你的资源分离到不同的域名确实会带来 DNS 和 TLS 解析额外时间的缺点。

了解更多关于 assetPrefix

配置缓存

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

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

next.config.js
module.exports = {
  cacheHandler: require.resolve("./cache-handler.js"),
  cacheMaxMemorySize: 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。

值得注意的是

  • revalidatePath 是缓存标签的一个便捷层。调用 revalidatePath 将为提供的页面调用 revalidateTag 函数,使用一个特殊的默认标签。

构建缓存

Next.js 在 next build 期间生成一个 ID 来识别正在提供的应用版本。相同的构建应该被用于启动多个容器。

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

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

版本偏差

Next.js 会自动缓解大多数 版本偏差 的实例,并在检测到时自动重新加载应用以获取新资源。例如,如果 deploymentId 不匹配,页面之间的转换将执行硬导航,而不是使用预取的值。

当应用重新加载时,如果它没有设计成在页面导航之间持久化,可能会丢失应用状态。例如,使用 URL 状态或本地存储会在页面刷新后保持状态。然而,像 useState 这样的组件状态在这种导航中会丢失。

Vercel 为 Next.js 应用提供额外的 偏差保护,以确保即使在新版本部署后,旧客户端仍然可以访问前一版本的资源和函数。

你可以在 next.config.js 文件中手动配置 deploymentId 属性,以确保每个请求使用 ?dpl 查询字符串或 x-deployment-id 头。

流式传输和 Suspense

Next.js App Router 在自托管时支持 流式响应。如果你使用 Nginx 或类似的代理,你需要配置它以禁用缓冲以启用流式传输。

例如,你可以通过将 X-Accel-Buffering 设置为 no 来在 Nginx 中禁用缓冲:

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: "/:path*{/}?",
        headers: [
          {
            key: "X-Accel-Buffering",
            value: "no",
          },
        ],
      },
    ];
  },
};