Cloudflare
故障排除

故障排除

尝试部署到 Cloudflare Pages 而非 Cloudflare Workers?

@opennextjs/cloudflare 是专门为将 Next.js 应用部署到 Cloudflare Workers (opens in a new tab) 而构建的。

Cloudflare Workers 现已支持 Cloudflare Pages 的大部分功能,并且具备一些 Cloudflare Pages 尚未支持的特性。请参阅 Cloudflare Workers 文档中的 兼容性矩阵 (opens in a new tab)

如需部署到 Cloudflare Pages,可以使用 @cloudflare/next-on-pages,并按照 Cloudflare Pages 部署 Next.js 应用指南 (opens in a new tab) 操作。

"您的 Worker 超过了 3 MiB 的大小限制"

您正在部署的 Cloudflare 账户使用的是 Workers 免费计划,该计划 将每个 Worker 的大小限制为 3 MiB (opens in a new tab)。升级到 Workers 付费计划后,每个 Worker 的大小上限将提升至 10 MiB。

部署 Worker 时,wrangler 会显示原始大小和压缩后大小。只有后者(gzip 压缩后大小)会影响这些限制。

"您的 Worker 超过了 10 MiB 的大小限制"

如果您的 Worker 压缩后超过 10 MiB —— 可能是生产包中包含了不必要的代码。您可以通过以下方式可视化和分析:

  1. 在项目根目录运行 npx opennextjs-cloudflare build
  2. 进入 .open-next/server-functions/default 目录
  3. 获取名为 handler.mjs.meta.json 的文件,使用 ESBuild 包分析器 (opens in a new tab) 可视化应用代码,了解生产包中最大的组成部分

应用在导入特定 NPM 包时构建失败

首先,请确保在你的 wrangler 配置文件 (opens in a new tab)中启用了 nodejs_compat 兼容性标志,并且将兼容日期设置为 "2024-09-23" 或之后。有关 Cloudflare Workers 中 Node.js 支持的更多详情,请参考 Node.js Workers 文档 (opens in a new tab)

某些 NPM 包定义了多个导出项。例如:

"exports": {
    "other": "./src/other.js",
    "node": "./src/node.js",
    "browser": "./src/browser.js",
    "default": "./src/default.js"
},

当你使用 @opennextjs/cloudflare 时,Wrangler (opens in a new tab) 会在本地运行或部署到 Cloudflare 之前打包你的代码。Wrangler 在导入模块时需要选择使用哪个导出项。默认情况下,使用 esbuild (opens in a new tab) 的 Wrangler 处理方式可能与某些 NPM 包不兼容。

你可能需要修改 Wrangler 解析多个导出项的方式,以便在导入包时优先使用 node 导出项(如果存在)。可以通过在 Next.js 应用的根目录下的 .env 文件中定义以下变量来实现:

WRANGLER_BUILD_CONDITIONS=""
WRANGLER_BUILD_PLATFORM="node"

Error: Cannot perform I/O on behalf of a different request.(错误:无法代表不同请求执行 I/O 操作)

某些数据库客户端(如 postgres (opens in a new tab))在首次实例化时会创建到数据库服务器的连接,并在后续请求中复用该连接。这种编程模型与 Workers 运行时环境不兼容,因为在 Workers 中连接不能在不同请求间复用。

这种情况下会产生以下错误:

⨯ Error: Cannot perform I/O on behalf of a different request. I/O objects (such as streams, request/response bodies, and others) created in the context of one request handler cannot be accessed from a different request's handler. This is a limitation of Cloudflare Workers which allows us to improve overall performance. (I/O type: Writable)

要解决这个问题,你应该在请求上下文中创建数据库客户端,而不是维护一个全局的数据库客户端。

全局客户端将无法工作:

// src/lib/db.ts
import postgres from "postgres";
 
// `client` 是全局的
// 由于连接会在请求间共享,在 worker 中会失败
export const client = postgres(process.env.DATABASE_URL, { max: 5 });
 
// src/app/api/route.ts
import { client } from "@/db/db";
 
export const dynamic = "force-dynamic";
 
export async function GET() {
  return new Response(JSON.stringify(await client`SELECT * FROM users;`));
}

可以通过为每个传入请求创建客户端来修复:

// src/app/api/route.ts
export const dynamic = "force-dynamic";
 
export async function GET() {
  // 为每个传入请求创建客户端,连接不会在请求间共享
  const client = postgres(process.env.DATABASE_URL, { max: 5 });
  return new Response(JSON.stringify(await client`SELECT * FROM users;`));
}

错误:无法加载 chunk server/chunks/ssr/<chunk_name>.js

如果出现类似以下错误:

✘ [ERROR] ⨯ Error: Failed to load chunk server/chunks/ssr/<chunk_name>.js

      at loadChunkPath
  (...)
      at Object.loadChunk
  (...)
      at .open-next/server-functions/default/.next/server/app/page.js

这可能是由于您使用了 turbopack 构建 (next build --turbo),而 OpenNext 目前不支持该功能。 将构建命令改为 next build 即可解决此问题。

X [ERROR] 无法解析 "<package>"

在构建过程中出现以下错误时:

⚙️ 正在打包 OpenNext 服务器...

X [ERROR] Could not resolve "<package name>"

可能是因为该包包含 workerd 特定的代码。

请参阅此解决方案来解决问题。