cloudflare-pages
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCloudflare Pages
Cloudflare Pages
Deploy frontend projects with preview builds, edge functions, and global CDN delivery on Cloudflare's network.
在Cloudflare网络上部署前端项目,支持预览构建、边缘函数和全球CDN分发。
When to Use
使用场景
- Deploying static sites (React, Vue, Astro, Hugo, Next.js static export).
- Full-stack applications using Pages Functions for server-side logic.
- Projects that need automatic preview deployments per pull request.
- Teams that want zero-config CDN with custom domain and TLS.
- Migrating from Vercel, Netlify, or GitHub Pages to Cloudflare's ecosystem.
- 部署静态站点(React、Vue、Astro、Hugo、Next.js静态导出)。
- 使用Pages Functions实现服务端逻辑的全栈应用。
- 需要为每个拉取请求自动部署预览版本的项目。
- 想要零配置CDN、自定义域名及TLS支持的团队。
- 从Vercel、Netlify或GitHub Pages迁移至Cloudflare生态系统的场景。
Prerequisites
前置条件
- Node.js 18+ and npm installed locally.
- A Cloudflare account (free tier works for most projects).
- Wrangler CLI installed: .
npm install -g wrangler - Authenticated via or
wrangler loginenvironment variable.CLOUDFLARE_API_TOKEN - Source code in a Git repository (GitHub or GitLab for dashboard integration).
- 本地安装Node.js 18+及npm。
- 拥有Cloudflare账户(免费套餐适用于大多数项目)。
- 安装Wrangler CLI:。
npm install -g wrangler - 通过或
wrangler login环境变量完成身份验证。CLOUDFLARE_API_TOKEN - 源代码存储在Git仓库中(如需控制台集成,需使用GitHub或GitLab)。
Project Setup via Wrangler
通过Wrangler配置项目
Create a New Project
创建新项目
bash
undefinedbash
undefinedCreate a new Pages project
创建新的Pages项目
npx wrangler pages project create my-site
npx wrangler pages project create my-site
List existing projects
列出已有项目
npx wrangler pages project list
npx wrangler pages project list
Delete a project (removes all deployments)
删除项目(会移除所有部署)
npx wrangler pages project delete my-site
undefinednpx wrangler pages project delete my-site
undefinedDeploy from Local Build Output
从本地构建产物部署
bash
undefinedbash
undefinedBuild your framework first
先构建你的框架项目
npm run build
npm run build
Deploy the output directory
部署输出目录
npx wrangler pages deploy dist --project-name=my-site
npx wrangler pages deploy dist --project-name=my-site
Deploy with a custom branch name (triggers preview URL)
使用自定义分支名称部署(触发预览URL)
npx wrangler pages deploy dist --project-name=my-site --branch=feature-auth
npx wrangler pages deploy dist --project-name=my-site --branch=feature-auth
Deploy and get the deployment URL in JSON
部署并以JSON格式获取部署URL
npx wrangler pages deploy dist --project-name=my-site --branch=main 2>&1 | tail -1
undefinednpx wrangler pages deploy dist --project-name=my-site --branch=main 2>&1 | tail -1
undefinedList and Manage Deployments
列出并管理部署
bash
undefinedbash
undefinedList recent deployments
列出近期部署
npx wrangler pages deployment list --project-name=my-site
npx wrangler pages deployment list --project-name=my-site
Tail live logs from a deployment
实时查看部署日志
npx wrangler pages deployment tail --project-name=my-site --environment=production
undefinednpx wrangler pages deployment tail --project-name=my-site --environment=production
undefinedDashboard Git Integration
控制台Git集成
- Navigate to Workers & Pages > Create application > Pages.
- Connect your GitHub or GitLab account.
- Select the repository and configure:
- Production branch:
main - Build command:
npm run build - Build output directory: (or
dist,build,.nextdepending on framework)public
- Production branch:
- Set environment variables per environment (Production vs Preview).
- 前往Workers & Pages > 创建应用 > Pages。
- 连接你的GitHub或GitLab账户。
- 选择仓库并配置:
- 生产分支:
main - 构建命令:
npm run build - 构建输出目录:(根据框架不同,也可设置为
dist、build、.next)public
- 生产分支:
- 为不同环境(生产/预览)设置环境变量。
Framework Presets
框架预设
Cloudflare auto-detects frameworks. Override if needed:
| Framework | Build Command | Output Directory |
|---|---|---|
| React CRA | | |
| Vite | | |
| Next.js | | |
| Astro | | |
| Hugo | | |
| SvelteKit | | |
Cloudflare会自动检测框架,如有需要可手动覆盖:
| Framework | Build Command | Output Directory |
|---|---|---|
| React CRA | | |
| Vite | | |
| Next.js | | |
| Astro | | |
| Hugo | | |
| SvelteKit | | |
Preview Deployments
预览部署
Every non-production branch gets a unique preview URL automatically.
undefined每个非生产分支都会自动生成一个唯一的预览URL。
undefinedURL format for preview deployments
预览部署的URL格式
https://<commit-hash>.<project-name>.pages.dev
https://<branch-name>.<project-name>.pages.dev
undefinedhttps://<commit-hash>.<project-name>.pages.dev
https://<branch-name>.<project-name>.pages.dev
undefinedBranch-Based Access Control
基于分支的访问控制
bash
undefinedbash
undefinedSet preview branch patterns in wrangler.toml (Pages-specific)
在wrangler.toml中设置预览分支规则(Pages专属)
Or configure via dashboard: Settings > Builds & deployments
或通过控制台配置:设置 > 构建与部署
Include branches: feature/*, staging
包含分支:feature/*、staging
Exclude branches: dependabot/*
排除分支:dependabot/*
undefinedundefinedPreview Comment on Pull Requests
拉取请求的预览评论
Enable the Cloudflare Pages GitHub App to post deployment URLs as PR comments. Configure under Settings > Builds & deployments > Preview comment.
启用Cloudflare Pages GitHub应用,即可将部署URL作为PR评论发布。可在设置 > 构建与部署 > 预览评论中配置。
Pages Functions
Pages Functions
Pages Functions provide server-side logic deployed alongside your static site. Place files in a directory at the project root.
functions/Pages Functions可提供与静态站点一同部署的服务端逻辑。需将文件放置在项目根目录的文件夹中。
functions/Basic API Route
基础API路由
typescript
// functions/api/hello.ts
export const onRequestGet: PagesFunction = async (context) => {
return new Response(JSON.stringify({ message: "Hello from the edge" }), {
headers: { "Content-Type": "application/json" },
});
};
// functions/api/users/[id].ts — dynamic route parameter
export const onRequestGet: PagesFunction = async (context) => {
const userId = context.params.id;
return new Response(JSON.stringify({ userId }), {
headers: { "Content-Type": "application/json" },
});
};typescript
// functions/api/hello.ts
export const onRequestGet: PagesFunction = async (context) => {
return new Response(JSON.stringify({ message: "Hello from the edge" }), {
headers: { "Content-Type": "application/json" },
});
};
// functions/api/users/[id].ts — 动态路由参数
export const onRequestGet: PagesFunction = async (context) => {
const userId = context.params.id;
return new Response(JSON.stringify({ userId }), {
headers: { "Content-Type": "application/json" },
});
};Middleware
中间件
typescript
// functions/_middleware.ts — runs before all routes
export const onRequest: PagesFunction = async (context) => {
const authHeader = context.request.headers.get("Authorization");
if (!authHeader || !authHeader.startsWith("Bearer ")) {
return new Response("Unauthorized", { status: 401 });
}
return context.next();
};typescript
// functions/_middleware.ts — 在所有路由前执行
export const onRequest: PagesFunction = async (context) => {
const authHeader = context.request.headers.get("Authorization");
if (!authHeader || !authHeader.startsWith("Bearer ")) {
return new Response("Unauthorized", { status: 401 });
}
return context.next();
};Functions with Bindings
绑定资源的Functions
typescript
// functions/api/data.ts — using KV and D1 bindings
interface Env {
MY_KV: KVNamespace;
MY_DB: D1Database;
MY_BUCKET: R2Bucket;
}
export const onRequestGet: PagesFunction<Env> = async (context) => {
// Read from KV
const cached = await context.env.MY_KV.get("key");
if (cached) return new Response(cached);
// Query D1
const result = await context.env.MY_DB.prepare(
"SELECT * FROM items LIMIT 10"
).all();
// Cache in KV
await context.env.MY_KV.put("key", JSON.stringify(result.results), {
expirationTtl: 300,
});
return Response.json(result.results);
};typescript
// functions/api/data.ts — 使用KV和D1绑定
interface Env {
MY_KV: KVNamespace;
MY_DB: D1Database;
MY_BUCKET: R2Bucket;
}
export const onRequestGet: PagesFunction<Env> = async (context) => {
// 从KV读取数据
const cached = await context.env.MY_KV.get("key");
if (cached) return new Response(cached);
// 查询D1数据库
const result = await context.env.MY_DB.prepare(
"SELECT * FROM items LIMIT 10"
).all();
// 在KV中缓存数据
await context.env.MY_KV.put("key", JSON.stringify(result.results), {
expirationTtl: 300,
});
return Response.json(result.results);
};Wrangler Configuration
Wrangler配置
toml
undefinedtoml
undefinedwrangler.toml — Pages project configuration
wrangler.toml — Pages项目配置
name = "my-site"
compatibility_date = "2024-09-01"
pages_build_output_dir = "dist"
name = "my-site"
compatibility_date = "2024-09-01"
pages_build_output_dir = "dist"
KV namespace binding
KV命名空间绑定
[[kv_namespaces]]
binding = "MY_KV"
id = "abc123def456"
[[kv_namespaces]]
binding = "MY_KV"
id = "abc123def456"
D1 database binding
D1数据库绑定
[[d1_databases]]
binding = "MY_DB"
database_name = "my-app-db"
database_id = "xxxx-yyyy-zzzz"
[[d1_databases]]
binding = "MY_DB"
database_name = "my-app-db"
database_id = "xxxx-yyyy-zzzz"
R2 bucket binding
R2存储桶绑定
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "app-assets"
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "app-assets"
Environment variables
环境变量
[vars]
API_BASE_URL = "https://api.example.com"
undefined[vars]
API_BASE_URL = "https://api.example.com"
undefinedHeaders and Redirects
自定义头部与重定向
Custom Headers
自定义头部
undefinedundefinedpublic/_headers
public/_headers
/assets/*
Cache-Control: public, max-age=31536000, immutable
/*
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'
/api/*
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
undefined/assets/*
Cache-Control: public, max-age=31536000, immutable
/*
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'
/api/*
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
undefinedRedirects
重定向
undefinedundefinedpublic/_redirects
public/_redirects
/old-page /new-page 301
/blog/:slug /posts/:slug 301
/docs/* https://docs.example.com/:splat 302
/home / 302
undefined/old-page /new-page 301
/blog/:slug /posts/:slug 301
/docs/* https://docs.example.com/:splat 302
/home / 302
undefinedCustom Domains
自定义域名
bash
undefinedbash
undefinedAdd a custom domain via Cloudflare dashboard:
通过Cloudflare控制台添加自定义域名:
Pages project > Custom domains > Set up a custom domain
Pages项目 > 自定义域名 > 设置自定义域名
Or via API
或通过API添加
curl -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/pages/projects/my-site/domains"
-H "Authorization: Bearer $CF_API_TOKEN"
-H "Content-Type: application/json"
-d '{"name":"www.example.com"}'
-H "Authorization: Bearer $CF_API_TOKEN"
-H "Content-Type: application/json"
-d '{"name":"www.example.com"}'
undefinedcurl -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/pages/projects/my-site/domains"
-H "Authorization: Bearer $CF_API_TOKEN"
-H "Content-Type: application/json"
-d '{"name":"www.example.com"}'
-H "Authorization: Bearer $CF_API_TOKEN"
-H "Content-Type: application/json"
-d '{"name":"www.example.com"}'
undefinedCI/CD Integration
CI/CD集成
GitHub Actions
GitHub Actions
yaml
undefinedyaml
undefined.github/workflows/deploy.yml
.github/workflows/deploy.yml
name: Deploy to Cloudflare Pages
on:
push:
branches: [main]
pull_request:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run build
- uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy dist --project-name=my-site
undefinedname: Deploy to Cloudflare Pages
on:
push:
branches: [main]
pull_request:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run build
- uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy dist --project-name=my-site
undefinedTroubleshooting
故障排查
| Symptom | Cause | Fix |
|---|---|---|
| Build fails with out-of-memory | Build exceeds 1 GB RAM limit | Reduce dependencies; use |
| Functions return 404 | | Move |
| Preview URL shows old content | Browser cache or stale deployment | Hard refresh; check deployment list for latest commit hash |
| Custom domain shows SSL error | DNS not proxied through Cloudflare | Enable orange cloud (proxy) on the CNAME record |
| File not in build output directory | Place in |
| Bindings undefined in Functions | Missing | Add bindings in |
| 1 MB function size limit exceeded | Too many dependencies bundled | Tree-shake; move large deps to KV or R2 |
| 症状 | 原因 | 解决方法 |
|---|---|---|
| 构建因内存不足失败 | 构建超出1GB内存限制 | 减少依赖;使用 |
| Functions返回404 | | 将 |
| 预览URL显示旧内容 | 浏览器缓存或部署版本过期 | 强制刷新;查看部署列表确认最新提交哈希 |
| 自定义域名显示SSL错误 | DNS未通过Cloudflare代理 | 在CNAME记录上启用橙色云(代理) |
| 文件不在构建输出目录中 | 将其放置在 |
| Functions中绑定资源未定义 | | 在 |
| 超出1MB函数大小限制 | 打包了过多依赖 | 摇树优化;将大型依赖移至KV或R2 |
Related Skills
相关技能
- cloudflare-workers - Edge backend logic and API routes
- cloudflare-r2 - Object storage for assets and uploads
- cloudflare-zero-trust - Protect preview deployments with Access policies
- cdn-setup - General CDN configuration patterns
- cloudflare-workers - 边缘后端逻辑与API路由
- cloudflare-r2 - 用于资源与上传的对象存储
- cloudflare-zero-trust - 使用访问策略保护预览部署
- cdn-setup - 通用CDN配置模式