跳转到内容

@astrojs/ cloudflare

@astrojs/cloudflare 是一个与 Cloudflare Pages Functions 目标一起使用的 SSR 适配器。你可以使用 Astro/Javascript 编写代码,并将其部署到 Cloudflare Pages。

通过以下 astro add 命令将 Cloudflare 适配器添加到你的 Astro 项目中,以启用 SSR。这将安装适配器,并在这一步之内对 astro.config.mjs 文件进行相应的更改。

Terminal window
# 使用 NPM
npx astro add cloudflare
# 使用 Yarn
yarn astro add cloudflare
# 使用 PNPM
pnpm astro add cloudflare

如果你更喜欢手动安装适配器,请完成以下两个步骤:

  1. 使用你喜欢的包管理器安装 Cloudflare 适配器到项目的依赖项中。如果你使用 npm 或不确定,可以在终端中运行:
Terminal window
npm install @astrojs/cloudflare
  1. 将以下内容添加到你的 astro.config.mjs 项目文件中:
astro.config.mjs
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
output: 'server',
adapter: cloudflare(),
});

mode: "advanced" | "directory"

默认为 "advanced"

这个配置选项定义了你的 Astro 项目如何部署到 Cloudflare Pages。

  • advanced 模式会获取 dist 文件夹中的 _worker.js 文件。
  • directory 模式会获取 functions 文件夹中的文件,默认只会生成一个 [[path]].js 文件。

切换到 directory 模式允许你手动添加额外的文件例如 Cloudflare Pages 插件Cloudflare Pages 中间件 甚至使用了 Cloudflare Pages 函数路由 的自定义函数。

astro.config.mjs
export default defineConfig({
adapter: cloudflare({ mode: 'directory' }),
});

要为每个页面编译单独的包,请在你的 Cloudflare 适配器配置中设置 functionPerRoute 选项。该选项需要手动维护 functions 文件夹。Astro 生成的文件将覆盖 functions 文件夹中具有相同名称的现有文件,因此你必须为手动添加的每个文件选择唯一的文件名。此外,适配器永远不会清空 functions 文件夹中过时的文件,因此当你删除页面时,你必须手动清理文件夹。

astro.config.mjs
import {defineConfig} from "astro/config";
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
adapter: cloudflare({
mode: 'directory',
functionPerRoute: true
})
})

该适配器不支持 edgeMiddleware 选项。

routes.strategy: "auto" | "include" | "exclude"

默认值:"auto"

在没有提供自定义 _routes.json 的情况下决定 routes.json 该如何被生成。

这有三个选项可供选择:

  • "auto"(默认):自动选择生成最少条目的策略。这通常应该够用了,除非你有某些理由要选择其他选项。

  • include:不会被预渲染的页面和端点将会被列为 include 条目,并告诉 Cloudflare 将这些路由作为函数调用。而 exclude 条目仅用于解决冲突。通常情况下,如果你的网站大多数是静态页面,只有少数动态页面或端点时,这将是最好的策略。

    示例:对于 src/pages/index.astro(静态),src/pages/company.astro(静态),src/pages/users/faq.astro(静态),以及 /src/pages/users/[id].astro (SSR),将产生以下 _routes.json:

    {
    "version": 1,
    "include": [
    "/_image", // Astro 的图片端点
    "/users/*" // 动态路由
    ],
    "exclude": [
    // 排除上述动态通配符路由中后的静态路由
    "/users/faq/",
    "/users/faq/index.html"
    ]
    }
  • exclude 预渲染的页面将被列为 exclude 条目(即告诉 Cloudflare 将这些路由作为静态资源处理)。通常情况下,如果你的网站大多数是动态页面或端点,只有少数静态页面时,这将是最好的策略。

    示例:对于前面示例中相同的页面,这将产生以下 _routes.json:

    {
    "version": 1,
    "include": [
    "/*" // 除了后面的路由外,所有路由都会被作为函数处理
    ],
    "exclude": [
    // 所有静态资源
    "/",
    "/company/",
    "/index.html",
    "/users/faq/",
    "/favicon.png",
    "/company/index.html",
    "/users/faq/index.html"
    ]
    }

routes.include: string[]

默认值:[]

如果你想使用自动生成的 _routes.json,但又想要包含额外的路由(例如,当你在 functions 文件夹中有自定义函数时),那么你可以使用 routes.include 选项将额外的路由添加到 include 数组中。

routes.exclude: string[]

默认值:[]

如果你想要使用自动生成的 _routes.json,但又想要排除其他的路由,那么你可以使用 routes.exclude 选项将额外的路由到添加 exclude 数组中。

以下示例自动生成了 _routes.json,同时包含和排除额外的路由。请注意,如果你在 functions 文件夹中有自定义函数,那么这些函数将不会被 Astro 处理。

astro.config.mjs
export default defineConfig({
adapter: cloudflare({
mode: 'directory',
routes: {
strategy: 'include',
include: ['/users/*'], // 由自定义函数处理:functions/users/[id].js
exclude: ['/users/faq'], // 由静态页面处理:pages/users/faq.astro
},
}),
});

imageService: "passthrough" | "cloudflare"

控制适配器使用哪个图像服务。当配置了不兼容的图像服务时,适配器将默认到 passthrough 模式。否则,它将使用全局配置的图像服务:

wasmModuleImports: boolean

默认值:false

是否将 .wasm 文件直接作为 ES 模块导入。

wasmModuleImports: true 添加到 astro.config.mjs 以在 Cloudflare 构建和 Astro 开发服务器中启用该功能。

astro.config.mjs
import {defineConfig} from "astro/config";
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
adapter: cloudflare({
wasmModuleImports: true
}),
output: 'server'
})

查看 Cloudflare 的存储库以获取有关 CF_BINDING 的更多类型信息。

runtime: { mode: 'off' } | { mode: 'local'; type: 'pages'; persistTo?: string; bindings?: Record<string, CF_BINDING> } | { mode: 'local'; type: 'workers'; persistTo?: string; };

默认值:{ mode: 'off', persistTo: '' }

决定是否以及如何将 Cloudflare Runtime 添加到 astro dev。请阅读更多有关 Cloudflare Runtime 的信息。

type 属性定义了你的 Astro 项目将部署到哪:

mode 属性则定义了你希望运行时在 astro dev 中支持什么:

  • off:使用 astro dev 时无法访问运行时。当你需要访问运行时来模拟本地的生产环境时,可以选择使用 Wrangler 预览
  • local:使用由 miniflare 和 workerd 驱动的本地运行时,它支持 Cloudflare 绑定。只有当你想使用不支持的功能,如 eval,或没有本地支持的绑定时,才选择使用 Wrangler 预览

mode: local 中,你可以访问 persistTo 属性,它定义了本地绑定状态保存的位置。这避免了每次重启开发服务器时都刷新绑定。这个值是相对于你执行 astro dev 的路径的一个目录。默认情况下它被设置为 .wrangler/state/v3,以允许使用 wrangler 命令行工具(例如用于迁移)。将这个路径会添加到你的 .gitignore 中。

Cloudflare 运行时让你能够访问环境变量和 Cloudflare 绑定。你可以在 Cloudflare 的 WorkersPages 文档中找到更多信息。根据你的部署类型(pagesworkers),你需要以不同的方式配置绑定。

目前支持的绑定有:

Cloudflare Pages 不支持配置文件。

要将你的 pages 项目部署到生产环境,你需要使用 Cloudflare 的仪表盘来配置绑定。要在本地访问绑定,你需要使用适配器的 runtime 选项来配置它们。

astro.config.mjs
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
output: 'server',
adapter: cloudflare({
runtime: {
mode: 'local',
type: 'pages',
bindings: {
// 一个变量绑定的例子(环境变量)
"URL": {
type: "var",
value: "https://example.com",
},
// 一个 KV 绑定的例子
"KV": {
type: "kv",
},
// 一个 D1 绑定的例子
"D1": {
type: "d1",
},
// 一个 R2 绑定的例子
"R2": {
type: "r2",
},
// 一个 Durable Object 绑定的例子
"DO": {
type: "durable-object",
className: "DO",
},
},
},
}),
});

如果你还需要定义 secrets 以外的环境变量,你需要在 Astro 项目的根目录下添加一个 .dev.vars 文件:

.dev.vars
DB_PASSWORD=myPassword

如果你想使用 wrangler 进行命令行操作,比如 D1 迁移,你还需要在 Astro 项目的根目录下添加一个包含正确内容的 wrangler.toml 文件。请查阅Cloudflare 的文档以获取更多详细信息。

wrangler.toml
name = "example"
compatibility_date = "2023-06-14"
# example for D1 Binding
[[d1_databases]]
binding = "D1"
database_name = "D1"
database_id = "D1"
preview_database_id = "D1"

要将你的 workers 项目部署到生产环境,你需要在你的 Astro 项目的根目录中使用 wrangler.toml 配置文件来配置绑定。为了能够在本地访问绑定,@astrojs/cloudflare 适配器也会 wrangler.toml 从文件读取配置。

wrangler.toml
name = "example"
# 一个 KV 绑定的例子
kv_namespaces = [
{ binding = "KV", id = "KV", preview_id = "KV" },
]
# 一个变量绑定的例子(环境变量)
[vars]
URL = "example.com"
# 一个 D1 绑定的例子
[[d1_databases]]
binding = "D1"
database_name = "D1"
database_id = "D1"
preview_database_id = "D1"
# 一个 R2 绑定的例子
[[r2_buckets]]
binding = 'R2'
bucket_name = 'R2'
# 一个 Durable Object 绑定的例子
[[durable_objects.bindings]]
name = "DO"
class_name = "DO"

如果你还需要定义 secrets 以外的环境变量,你需要在 Astro 项目的根目录下添加一个 .dev.vars 文件:

.dev.vars
DB_PASSWORD=myPassword

在任意 .astro 文件中,你都可以直接通过 Astro.locals 从 Astro 组件中访问运行时:

src/pages/index.astro
---
const runtime = Astro.locals.runtime;
---
<pre>{JSON.stringify(runtime.env)}</pre>

你也可以通过 context.locals 从 API 端点访问运行时:

src/pages/api/someFile.js
export function GET(context) {
const runtime = context.locals.runtime;
return new Response('Some body');
}

如果你正在使用 advanced 运行时,那么你可以按以下方式声明 runtime 对象:

如果你已经配置了 mode:advanced,你可以使用 AdvancedRuntime 来为 runtime 对象添加类型:

src/env.d.ts
/// <reference types="astro/client" />
type KVNamespace = import('@cloudflare/workers-types/experimental').KVNamespace;
type ENV = {
SERVER_URL: string;
KV_BINDING: KVNamespace;
};
type Runtime = import('@astrojs/cloudflare').AdvancedRuntime<ENV>;
declare namespace App {
interface Locals extends Runtime {
user: {
name: string;
surname: string;
};
}
}

如果你已经配置了 mode: directory,你可以使用 DirectoryRuntime 来为 runtime 对象添加类型:

src/env.d.ts
/// <reference types="astro/client" />
type KVNamespace = import('@cloudflare/workers-types/experimental').KVNamespace;
type ENV = {
SERVER_URL: string;
KV_BINDING: KVNamespace;
};
type Runtime = import('@astrojs/cloudflare').DirectoryRuntime<ENV>;
declare namespace App {
interface Locals extends Runtime {
user: {
name: string;
surname: string;
};
}
}

你可以通过在 Astro 项目的 public/ 文件夹中添加一个 _headers 文件来附加 自定义头部 到你的响应中,该文件将被复制到构建输出目录中。

你可以使用 Cloudflare Pages 来声明 自定义重定向。这允许你将请求重定向到不同的 URL。你可以在 Astro 项目的 public/ 文件夹中添加一个 _redirects 文件,该文件将被复制到构建输出目录。

你可以使用 Cloudflare 路由 通过 _routes.json 文件来定义哪些路由会调用函数,哪些路由是静态资源。该文件由 Astro 自动生成。

默认情况下,@astrojs/cloudflare 会基于你应用的动态和静态路由生成一个 _routes.json 文件,当中包含了 includeexclude 规则。

这将使 Cloudflare 能够在没有函数调用的情况下提供文件和处理静态重定向。创建自定义的 _routes.json 将覆盖此自带的优化文件。参阅 Cloudflare 关于创建自定义 routes.json 的文档 了解更多细节。

以下是导入一个 Wasm 模块的示例,该模块通过将请求的数字参数相加来响应请求:

pages/add/[a]/[b].js
import mod from '../util/add.wasm?module';
// 预先初始化以共享同一个模块
const addModule: any = new WebAssembly.Instance(mod);
export async function GET(context) {
const a = Number.parseInt(context.params.a);
const b = Number.parseInt(context.params.b);
return new Response(`${addModule.exports.add(a, b)}`);
}

虽然这个例子很简单,但是 Wasm 可以用来加速在不涉及大量 I/O 的情况下的计算密集型操作,比如嵌入图像处理库。

Astro 的 Cloudflare 适配器允许你使用任何 Cloudflare 支持的 Node.js 运行时 API,例如:

  • assert
  • AsyncLocalStorage
  • Buffer
  • Crypto
  • Diagnostics Channel
  • EventEmitter
  • path
  • process
  • Streams
  • StringDecoder
  • util

如果要使用这些 API,你的页面或端点必须是服务器渲染的(而不是预渲染的),并使用 import {} from 'node:*' 导入语法。

pages/api/endpoint.js
export const prerender = false;
import { Buffer } from 'node:buffer';

另外,你需要在 Cloudflare 中启用兼容性标志。该标志的配置方法取决于你部署 Astro 站点的方式。更多详细指导,请参阅 启用 Node.js 兼容性的 Cloudflare 文档

所有 Cloudflare 的命名空间包(例如 cloudflare:sockets)都允许使用。但请注意,cloudflare:sockets 包在本地环境中需要使用 Wrangler 的开发模式才能正常工作。

为了使用 wrangler 在本地运行你的应用程序,请更新预览脚本:

package.json
"preview": "wrangler pages dev ./dist"

wrangler 能让你访问 Cloudflare 绑定环境变量cf 对象。要让热重载或 Astro 开发服务器与 Wrangler 工作,可能需要进行自定义设置。请参阅 社区示例

目前,在 Wrangler 中运行应用程序时由于代码被压缩,错误消息并不是很有用。为了更好地进行调试,你可以将 vite.build.minify = false 添加到你的 astro.config.js 文件中。

export default defineConfig({
adapter: cloudflare(),
output: 'server',
vite: {
build: {
minify: false,
},
},
});

寻求帮助,请查看 Discord#support 频道。我们友好的支持团队成员会在这里提供帮助!

你还可以查看我们的 Astro 集成文档 了解更多关于集成的信息。

该软件包由 Astro 核心团队维护。欢迎提交 issue 或 PR!

其他

UI 框架

SSR 适配器

其他