Cloudflare Pages部署Next.js服务指南
拒绝 Vercel ,拥抱 Cloudflare
部署一个Next.js网站
Next.js是一个开源的React框架,用于创建网站和应用程序。在本指南中,你将创建一个新的Next.js应用程序,并使用Cloudflare Pages进行部署。
本指南将指导你如何部署一个使用Edge Runtime的全栈Next.js项目,通过next-on-pages
适配器。
使用create-cloudflare
CLI (C3)创建一个新项目
create-cloudflare
CLI (C3)将为你的Next.js网站配置Cloudflare Pages。在终端中运行以下命令以创建一个新的Next.js网站:
$ npm create cloudflare@latest my-next-app -- --framework=next
C3将向你提出一系列设置问题。C3还将安装必要的依赖项,包括Wrangler CLI和@cloudflare/next-on-pages
适配器。
创建项目后,C3将使用默认的Next.js模板生成一个新的my-next-app
目录,并更新为与Cloudflare Pages完全兼容。
在创建新项目时,C3将给你一个选项,通过直接上传部署你应用程序的初始版本。你可以随时通过在项目目录中运行以下命令来重新部署你的应用程序:
$ npm run deploy
没有C3配置和部署项目
如果你已经有一个Next.js项目,或者希望在不使用C3的情况下手动创建和部署一个项目,Cloudflare建议你使用@cloudflare/next-on-pages
并参考其README以获取指令和额外信息,以帮助你开发和部署你的项目。
Git集成
除了直接上传部署外,你还可以通过对Git集成来部署项目。Git集成允许你将一个GitHub或GitLab仓库连接到你的Pages应用程序,并在每次推送新提交后自动构建和部署你的Pages应用程序。
设置需要对Git有基本的了解。如果你是Git新手,请参考GitHub的Git手册摘要,了解如何在本地机器上设置Git。
创建一个新的GitHub仓库
通过访问repo.new创建一个新的GitHub仓库。创建新仓库后,转到你新创建的项目目录,并通过在终端中运行以下命令来准备并将你的本地应用程序推送到GitHub:
$ git init
$ git add .
$ git commit -m "Initial commit"
$ git branch -M main
$ git remote add origin https://github.com/<your-gh-username>/<repository-name>
$ git push -u origin main
通过Cloudflare仪表板将你的应用程序连接到GitHub仓库
- 登录到Cloudflare仪表板并选择你的账户。
- 在账户首页,选择Workers & Pages > 创建应用程序 > Pages > 连接到Git。
如果你还没有这样做,系统会要求你授权访问你的GitHub账户。Cloudflare需要这样做,以便它可以监控并从源头部署你的项目。如果你愿意,可以将访问权限限制为特定仓库。但是,当你想要将更多仓库添加到Cloudflare Pages时,你需要在GitHub设置中手动更新这个列表。
- 选择你创建的新GitHub仓库,并在设置构建和部署部分提供以下信息:
配置选项值
生产分支main
构建命令
npx @cloudflare/next-on-pages@1
构建目录
.vercel/output/static
可选地,你可以自定义项目名称字段。它默认为GitHub仓库的名称,但不需要匹配。项目名称的值将被分配为你的*.pages.dev
子域。
- 完成配置后,选择保存并部署。
你将能够查看你的第一个部署管道的进度。Pages安装所有依赖项并按照指定构建项目。Cloudflare Pages将在每次推送新提交后自动重新构建并部署你的项目。
此外,你将可以访问预览部署,这些部署为拉取请求重复构建和部署过程。通过这些,你可以在将更改部署到生产环境之前,通过真实URL预览项目中的更改。
在你的Next.js应用程序中使用绑定
绑定允许你的应用程序与Cloudflare开发人员产品进行交互,例如KV、Durable Objects、R2和D1。
如果你打算在项目中使用绑定,你必须首先为本地和远程开发设置你的绑定。
为本地开发设置绑定
要在本地开发中设置绑定,你将使用由@cloudflare/next-on-pages/next-dev
提供的setupDevPlatform
函数。setupDevPlatform
根据你项目的wrangler.toml
文件设置一个平台仿真,你的Next.js应用程序可以在当地使用。
例如,要在本地使用KV绑定,打开Next.js配置文件并添加:
next.config.mjs
import { setupDevPlatform } from '@cloudflare/next-on-pages/next-dev'
if (process.env.NODE_ENV === 'development') {
await setupDevPlatform()
}
const nextConfig = {}
export default nextConfig
next.config.js / next.config.cjs
if (process.env.NODE_ENV === "development") {
const { setupDevPlatform } = require("@cloudflare/next-on-pages/next-dev")
setupDevPlatform()
}
const nextConfig = {}
module.exports = nextConfig
确保在项目根目录下有一个wrangler.toml
文件,其中包含一个名为MY_KV
的KV绑定的声明:
wrangler.toml
name = "my-next-app"
compatibility_flags = ["nodejs_compat"]
[[kv_namespaces]] binding = "MY_KV"
id = "<YOUR_KV_NAMESPACE_ID>"
为部署的应用程序设置绑定
要在部署的应用程序中访问绑定,你需要配置任何必要的绑定,并通过Cloudflare仪表板中的项目设置页面将它们连接到你的项目。
在Typescript项目中添加绑定
如果你的项目使用TypeScript,你将希望设置适当的类型支持,以便你可以以类型安全和方便的方式访问你的绑定。
要获得适当的类型支持,你需要在项目中创建一个新的env.d.ts
文件,并使用你的绑定扩展CloudflareEnv
(由getRequestContext
使用)接口。
以下是如何添加一个KVNamespace
绑定的示例:
env.d.ts
interface CloudflareEnv {
MY_KV: KVNamespace
}
在应用程序中访问绑定
本地和远程绑定可以使用@cloudflare/next-on-pages
公开的getRequestContext
函数访问。以下代码示例展示了如何在App Router应用程序的hello
API路由中访问它们。
app/api/hello/route.js
import { getRequestContext } from '@cloudflare/next-on-pages'
export const runtime = 'edge'
export async function GET(request) {
const myKv = getRequestContext().env.MY_KV
const kvValue = await myKv.get(`kvTest`) || false
return new Response(`The value of kvTest in MY_KV is: ${kvValue}`)
}
app/api/hello/route.ts
import type { NextRequest } from 'next/server'
import { getRequestContext } from '@cloudflare/next-on-pages'
export const runtime = 'edge'
export async function GET(request: NextRequest) {
const myKv = getRequestContext().env.MY_KV
const kvValue = await myKv.get(`kvTest`) || false
return new Response(`The value of kvTest in MY_KV is: ${kvValue}`)
}
Image
组件
Cloudflare网络不提供与Vercel网络相同的图像优化支持。因此,Next.js的<Image/>
组件在Cloudflare网络中的行为与在Vercel网络中不同。
- 如果你将应用程序构建为静态站点,
<Image/>
组件将不会提供任何图像。 - 如果你使用
@cloudflare/next-on-pages
构建你的应用程序,组件将工作,但它不会执行任何图像优化(无论你传递给它什么属性)。
这两种情况都可以通过为<Image />
组件设置适当的加载器来改进,这允许你使用任何你想要的图像优化服务。要使用Cloudflare Images,请参考使用Cloudflare Workers进行调整大小。
推荐的开发工作流程
当开发一个next-on-pages
应用程序时,这是Cloudflare推荐的开发工作流程:
使用标准的Next.js开发服务器进行开发
由Next.js提供的标准开发服务器是快速且精致的开发体验的最佳选择。next-dev
子模块(如在本地绑定部分所述)使得在使用Cloudflare绑定的同时,仍然可以使用Next.js的标准开发服务器。
在本地构建和预览你的应用程序
为了确保你的应用程序正在以完全兼容Cloudflare Pages的方式构建,在部署它之前,或者在你希望在开发过程中检查应用程序的正确性时,你将希望使用Cloudflare的workerd
JavaScript运行时在本地构建和预览它。
如果你使用C3创建了你的项目,请通过运行以下命令来执行此操作:
如果你没有使用C3创建你的项目,请运行:
$ npx @cloudflare/next-on-pages@1
并通过运行以下命令预览你的项目:
$ npx wrangler pages dev .vercel/output/static
部署你的应用程序并迭代
在本地预览你的应用程序后,你可以将它部署到Cloudflare Pages(通过直接上传或Git集成),并迭代这个过程以进行新的变化。
故障排除
在开发使用next-on-pages
的Next.js应用程序时,你可能会遇到一些常见错误和问题。以下是一些可能遇到的问题:
Edge运行时
当你的Next.js项目在Cloudflare Pages上运行时,所有服务器端路由都必须配置为Edge运行时路由。你必须在每个单独的服务器端路由中添加export const runtime = 'edge'
。
应用路由器
未找到
Next.js在构建过程中为你的应用程序生成一个not-found
路由。在某些情况下,Next.js可以检测到路由需要服务器端逻辑(特别是如果在根布局组件中执行计算),并且Next.js可能会创建一个Node.js无服务器函数(这与@cloudflare/next-on-pages
不兼容)。
为了防止这种不兼容性,Cloudflare建议始终提供一个自定义的not-found
路由,该路由明确选择Edge运行时:
(src/)app/not-found.(jsx|tsx)
export const runtime = 'edge'
export default async function NotFound() {
return (
)
}
generateStaticParams
当你在/app
目录中进行静态站点生成(SSG)并使用generateStaticParams
函数时,Next.js默认尝试按需处理非静态生成路由的请求。它通过创建一个Node.js无服务器函数来实现这一点(因此与@cloudflare/next-on-pages
不兼容)。
在这种情况下,你需要通过指定一个false
的dynamicParams
来指示Next.js不要这样做:
app/my-example-page/[slug]/page.jsx+
export const dynamicParams = false
// ...
顶级getRequestContext
getRequestContext
函数不能在路由文件的顶层调用,也不能以任何触发函数调用作为文件初始化的一部分的方式调用。
getRequestContext
必须在请求处理逻辑中调用,而不是以一种全局/无条件的方式触发,一旦文件被导入就会触发。
例如,以下是getRequestContext
的不正确用法:
app/api/myvar/route.js
import { getRequestContext } from '@cloudflare/next-on-pages'
export const runtime = 'edge'
const myVariable = getRequestContext().env.MY_VARIABLE
export async function GET(request) {
return new Response(myVariable)
}
上述示例可以通过以下方式修复:
app/api/myvar/route.js
import { getRequestContext } from '@cloudflare/next-on-pages'
export const runtime = 'edge'
export async function GET(request) {
const myVariable = getRequestContext().env.MY_VARIABLE
return new Response(myVariable)
}
页面路由器
getStaticPaths
当你在/pages
目录中进行静态站点生成(SSG)并使用getStaticPaths
函数时,Next.js默认尝试按需处理非静态生成路由的请求。它通过创建一个Node.js无服务器函数来实现这一点(因此与@cloudflare/next-on-pages
不兼容)。
在这种情况下,你需要通过指定一个错误的fallback
来指示Next.js不要这样做:
pages/my-example-page/[slug].jsx
// ...
export async function getStaticPaths() {
// ...
return {
paths,
fallback: false,
}
}
了解更多
如果觉得这篇文章有见地,不妨给我的 Saasfly 项目点个 Star ⭐️,或者分享给更多对开源感兴趣的朋友们。感谢支持!
---------------------
本内容依据 CC BY-NC-SA 4.0 DEED 许可证进行授权。转载请附上出处链接。