跳到主要内容

《林一的 Cloudflare 通关记》第 4 篇-给网站安个"家"——Cloudflare Pages 部署前端

· 阅读需 20 分钟

《林一的 Cloudflare 通关记》第4篇

周三下午,老张给林一发了一条消息:「把星火AI的前端代码推到GitHub上,然后部署起来。」

林一精神一振——终于可以干正事了。他熟练地 git initgit push,代码推到了GitHub仓库。然后,他打开了某云服务商的控制台,开始挑选云服务器。

故事:林一的手差点按下了"购买"按钮

「2核4G……嗯,够跑一个nginx了。按量付费,一个月大概六七十块……」

就在他的鼠标即将点击"立即购买"的那一刻,一只手从背后伸出来,按住了他的手腕。

「你一个月实习工资多少?」老张的声音从身后传来。

「三千……」

「服务器一个月七十,域名一年五十,SSL证书……哦证书咱用Cloudflare的免费的。但服务器钱,你打算自己掏?」

「公司不是可以报销吗?」

老张叹了口气:「报销流程走完要两个月。小王明天就要看线上效果,你等得起?」

林一收回了手。「那张哥,怎么办?」

老张拉了把椅子坐下来:「你听说过 Cloudflare Pages 吗?」

「Pages?像GitHub Pages那样?只能放静态页面?」

「此Pages非彼Pages。」老张笑了,「Cloudflare Pages 可不是简单放几个HTML文件。它能直接连你的GitHub仓库,你push代码它自动构建、自动部署、自动分发到全球CDN——而且,免费。」

「免费?连服务器都不用买?」

「不用买服务器,不用装nginx,不用配HTTPS,不用搞CI/CD pipeline。你只要把代码推到GitHub,剩下的Cloudflare全包了。」

林一将信将疑:「真有这么好的事?那我的React项目也能部署?」

「React、Vue、Next.js、Astro、SvelteKit……主流框架全支持。来,我给你讲讲这背后的原理。」


技术讲解:从"租房"到"拎包入住"

一、静态网站 vs 动态网站:餐厅的两种模式

「在讲Pages之前,先搞清楚一个基本概念。」老张在白板上写了两个词:静态动态

「你去一家餐厅吃饭,有两种模式。」

静态网站 就像一家预制菜餐厅——所有菜品提前做好,摆在取餐台上。顾客一来,直接端走吃,不需要厨师现场操作。速度快、成本低,但菜品是固定的,不能现点现做。

HTML、CSS、JS文件提前生成好,放在服务器上,用户访问时直接返回这些文件。没有数据库查询,没有服务端渲染,没有实时计算。

动态网站 就像一家现炒餐厅——顾客点了菜,厨师才开始切菜、炒菜、调味。每道菜都是现做的,可以根据顾客要求调整(少辣、不加香菜)。但你需要请厨师、备厨房,出餐也慢一些。

PHP、Java、Node.js这些后端服务,每次收到请求都要查询数据库、拼装HTML、再返回给用户。功能强,但成本高、维护复杂。

「那我的星火AI前端是哪种?」林一问。

「你的前端是React写的,构建之后生成一堆静态文件——HTML、JS、CSS。这本质上是静态网站。但你的AI功能需要调后端API对吧?这个后端后面用Workers解决。前端本身,用Pages托管就够了。」

老张画了一张对比图:

传统动态网站:  用户 → 服务器 → 查数据库 → 拼HTML → 返回
静态网站: 用户 → CDN → 直接返回HTML/JS/CSS
JAMstack网站: 用户 → CDN → 返回静态页面 → 页面通过JS调API获取动态数据

三种网站架构对比

「第三种就是我们要用的架构——JAMstack。」

二、JAMstack:现代前端的"预制菜+外卖"模式

老张在白板上写下了三个字母:J-A-M

「JAMstack不是某个具体的技术,而是一种架构理念。它把网站拆成了三层:」

J — JavaScript(动态交互)

页面上的所有动态行为都通过JavaScript在浏览器端完成。页面跳转、表单验证、数据渲染,全靠JS。React、Vue、Svelte这些框架就是干这个的。

A — API(后端服务)

需要动态数据怎么办?不通过服务端渲染,而是通过JS在浏览器里直接调API。API可以是自己的后端,也可以是第三方服务。前端和后端完全解耦,通过HTTP接口通信。

M — Markup(静态标记)

网页的HTML内容在构建时(build time)就生成好了,而不是在用户请求时(request time)动态拼装。构建工具(如Vite、Webpack)把React/Vue组件编译成静态HTML+JS文件。

「用餐厅打比方,」老张说,「JAMstack就是:预制菜提前做好摆在取餐台上(Markup),顾客自己来取(CDN分发),如果需要热一下或者加点调料,自己用微波炉搞定(JavaScript),想加个荷包蛋?单独找厨师点(API)。

林一恍然大悟:「这不就是我天天点的外卖模式嘛!主菜提前做好,饮料单独加。」

「没错。JAMstack的核心优势就是:静态内容走CDN,快如闪电;动态数据走API,按需获取。 两者各司其职,互不拖累。」

JAMstack 三层架构

老张总结了JAMstack的好处:

优势说明
速度静态文件走CDN,毫秒级响应,不用等服务器查数据库
安全没有传统服务器,攻击面大幅缩小,SQL注入都不存在了
成本静态文件托管几乎零成本,Pages免费套餐就够用
可扩展CDN天然支持高并发,不用担心服务器扛不住
开发体验前后端分离,前端独立部署,后端API独立迭代

「这跟国内的Serverless架构思路类似,」老张补充道,「比如腾讯云的静态网站托管、阿里云的OSS+CDN方案,本质都是把静态前端和动态后端拆开。区别是Cloudflare Pages把Git集成、自动构建、全球CDN一把梭全包了,体验更丝滑。」

三、Cloudflare Pages 工作原理:一条push,全球上线

「好了,概念讲完了。来看看Cloudflare Pages到底怎么工作的。」

老张画了一张流程图:

开发者 push 代码 → GitHub/GitLab 仓库

Cloudflare Pages 监听到 push 事件

拉取代码 → 执行构建命令(如 npm run build)

生成静态文件(dist/ 目录)

上传到 Cloudflare 全球 CDN

用户访问 → 就近节点返回内容

Pages 自动部署流程

「整个过程全自动。你只需要做一件事:push代码。」

老张解释了几个关键环节:

1. Git集成

Pages支持GitHub和GitLab两种Git提供商。你授权Cloudflare访问你的仓库后,每次push代码,Cloudflare都会收到通知并触发构建。就像你给快递公司设了一个自动取件点——包裹一放上去,快递员自动来取。

2. 自动构建

Cloudflare会在它的构建服务器上执行你指定的构建命令(比如 npm run build),把源代码编译成静态文件。构建环境预装了Node.js、Python、Go等常用运行时,也支持通过环境变量指定Node版本。

3. 全球CDN分发

构建完成后,静态文件会被推送到Cloudflare的全球CDN网络——还记得第3篇讲的那330多个城市的边缘节点吗?文件会被自动分发到这些节点上。用户访问时,直接从最近的节点获取,不用回源。

「这跟你之前用ngrok映射本地完全不是一个量级,」老张说,「ngrok是把你的电脑当服务器,电脑关了网站就没了。Pages是把文件放到全球330多个城市的CDN节点上,你的电脑关了?网站照样活蹦乱跳。」

林一有点不好意思地摸了摸头。

4. 内置HTTPS

还记得第2篇配SSL/TLS的痛苦吗?Pages自动给你配好了HTTPS。每个Pages项目都会获得一个 *.pages.dev 的域名,自带SSL证书。绑定自定义域名时,证书也自动签发。全程不用你操心想证书的事。

四、连接GitHub自动部署:手把手操作

「理论够了,上手操作。」老张拉过林一的键盘。

步骤一:创建Pages项目

  1. 登录 Cloudflare Dashboard → 左侧菜单 Workers & Pages

  2. 点击 Create applicationPagesConnect to Git

  3. 首次使用会弹出GitHub授权页面,授权Cloudflare访问你的仓库。你可以选择授权所有仓库,也可以只授权指定仓库。

老张提醒:「授权的时候注意,如果你选'All repositories',Cloudflare可以访问你账号下所有仓库。建议只选择需要部署的那个仓库,最小权限原则。」

步骤二:选择仓库并配置项目

  1. 授权完成后,会显示你的仓库列表。选择 spark-ai-frontend 仓库。

  2. 点击 Install & AuthorizeBegin setup,进入构建配置页面。

  3. Project name:输入 spark-ai。这个名字会生成你的默认域名 spark-ai.pages.dev

  4. Production branch:选择 main。这个分支的代码会部署到生产环境,其他分支会生成预览部署。

老张解释:「Production branch就是你正式上线用的分支。一般用 mainmaster。开发的时候在别的分支上改,改完提PR合并到main,Pages就会自动更新生产环境。」

步骤三:配置构建设置

  1. Set up builds and deployments 区域配置:
Framework preset:     React (Vite)      ← 根据你的框架选择
Build command: npm run build ← 框架的构建命令
Build output directory: dist ← 构建产物所在的目录

「如果你用的框架在预设列表里,选了之后构建命令和输出目录会自动填好,不用自己查。」老张说。

官方文档里列出的常见框架预设:

框架构建命令构建输出目录
React (Vite)npm run builddist
Vuenpm run builddist
Next.js (Static Export)npx next buildout
Nuxt.jsnpm run builddist
Astronpm run builddist
SvelteKitnpm run build.svelte-kit/cloudflare
Docusaurusnpm run buildbuild
Hugohugopublic

老张补充:「如果你的项目不需要构建步骤(比如纯HTML网站),构建命令留空就行。Pages会直接把仓库里的文件当成静态资源部署。」

  1. 如果你的项目不在仓库根目录(比如monorepo),在 Root directory (advanced) 里填上子目录路径。

步骤四:配置环境变量

  1. Environment variables (optional) 区域添加构建时需要的环境变量:
NODE_VERSION = 18        ← 指定Node.js版本
VITE_API_URL = https://api.spark-ai.com ← 前端需要的API地址

「环境变量在构建时注入,」老张解释,「比如你的前端代码里用 import.meta.env.VITE_API_URL 读取API地址,构建时Pages会把它替换成实际值。」

Cloudflare还会自动注入一些系统环境变量,你在构建脚本里可以直接使用:

系统变量含义
CI值为 true,表示在CI环境运行
CF_PAGES值为 1,表示在Cloudflare Pages环境运行
CF_PAGES_COMMIT_SHA当前提交的Git commit hash
CF_PAGES_BRANCH当前构建的分支名
CF_PAGES_URL本次部署的URL地址

「这些变量挺有用的,」老张说,「比如你可以在构建脚本里判断 CF_PAGES_BRANCH 是不是 main,来决定用生产环境的API地址还是测试环境的。」

步骤五:部署

  1. 点击 Save and Deploy

构建日志会实时输出——安装依赖、执行构建命令、上传文件。整个过程通常1-3分钟。

  1. 构建完成后,你会得到一个 https://spark-ai.pages.dev 的地址,打开就能看到你的网站了。

「以后每次你push代码到main分支,」老张说,「Pages会自动触发构建,1分钟内新版本就上线了。不用手动部署,不用SSH登录服务器,不用重启nginx。push即上线。」

林一看着自己的网站在浏览器里打开,有点激动:「这也太爽了吧?」

五、预览部署:每个PR都是一个"试验田"

「等一下,还有个更爽的功能。」老张说。

「你在开发新功能的时候,肯定不想直接改main分支吧?你会开一个新分支,改完提PR。但问题是,怎么让团队看到你的改动效果?以前你得自己部署一个测试环境,现在Pages帮你做了。」

预览部署(Preview Deployments) 的工作方式:

  1. 你从main分支切出一个新分支 feature/chat-ui
  2. push到GitHub后,Pages自动触发一次构建
  3. 生成一个唯一的预览URL:https://373f31e2.spark-ai.pages.dev
  4. 这个URL会随每次push到该分支而更新
  5. 在GitHub的PR页面,Cloudflare会自动评论,附上预览链接
main 分支 → 部署到生产环境 spark-ai.pages.dev
feature/chat-ui 分支 → 部署到预览环境 373f31e2.spark-ai.pages.dev

老张解释了预览部署的几个特点:

分支别名:除了hash形式的URL,Pages还会为每个分支创建一个别名URL。比如 feature/chat-ui 分支的别名是 feature-chat-ui.spark-ai.pages.dev(分支名转小写,非字母数字字符替换为连字符)。这个别名始终指向该分支的最新部署。

老张提醒:「分支别名很方便,但也意味着别名URL会随push而变化。如果你想把某个特定版本固定下来,用hash形式的URL——那个是永久的、不可变的。」

SEO友好:预览部署默认会带上 X-Robots-Tag: noindex 响应头,告诉搜索引擎不要索引这些临时URL。不用担心预览环境影响你的SEO排名。

访问控制:默认预览URL是公开的,任何人都能访问。但你可以通过Cloudflare Access给预览部署加上访问控制,只有团队成员才能查看。这在开发未发布功能时很有用。

开启方式:项目Settings → General → Enable access policy

「这个功能太实用了,」林一感叹,「以前给小王看效果,要么截图发企微,要么ngrok映射。现在一个PR链接丢过去,他自己点开看。」

「而且预览环境跟生产环境用的是同一套构建流程、同一套CDN,效果完全一致。不像ngrok,本地环境跟线上环境经常有差异。」

预览部署 vs 生产部署

六、构建配置进阶:避坑指南

林一第一次构建就报错了。构建日志显示:

12:03:45  Cloning repository...
12:03:48 Found project at /opt/buildhome/repo
12:03:48 Installing dependencies...
12:03:50 npm ERR! code ENOTSUP
12:03:50 npm ERR! notsup Required: {"node":">=18.0.0"}
12:03:51 npm ERR! notsup Actual: {"npm":"8.19.2","node":"v16.20.0"}

「Node版本不对,」老张瞥了一眼,「你项目的 package.json 里要求Node 18以上,但Pages默认用的是Node 16。加个环境变量指定版本。」

在项目的 Settings → Environment variables 里添加:

NODE_VERSION = 18

重新触发构建,这次成功了。

老张又补充了几个常见的构建坑:

坑1:构建输出目录写错

「Vue + Vite的输出目录是 dist,但有些框架不是。比如Gatsby是 public,Next.js静态导出是 out,Docusaurus是 build。目录写错了,Pages会找不到文件,部署成功但页面404。」

**坑2:路径大小写问题」

「本地开发是macOS,文件系统不区分大小写。但Pages的构建环境是Linux,区分大小写。你 import Header from './components/Header.jsx',但文件实际叫 header.jsx,本地能跑,Pages上构建报错。」

「这个坑我踩过!」林一说,「找了一小时才发现。」

**坑3:.gitignore 忽略了构建配置文件」

「有些同学把 .env 文件gitignore了,但构建配置依赖它。本地能构建,Pages上找不到配置就挂了。环境变量一定要在Pages后台也配一份。」

构建三大常见坑

七、自定义域名:让网站姓"自己"

「现在你的网站在 spark-ai.pages.dev 上跑着,」老张说,「但我们第1篇就注册了 spark-ai.com 这个域名,得把它绑上。」

绑定自定义域名的步骤很简单:

  1. 进入Pages项目 → Custom domainsSet up a domain
  2. 输入域名 spark-ai.com(或子域名 app.spark-ai.com
  3. 点击 Continue

因为 spark-ai.com 已经托管在Cloudflare的DNS上了(第1篇的操作),Cloudflare会自动帮你创建CNAME记录,指向你的Pages项目。SSL证书也会自动签发——还记得第2篇讲的边缘证书吗?全自动,不用你管。

「如果你的域名不在Cloudflare上,」老张补充,「你需要手动在DNS服务商那边加一条CNAME记录,指向 <你的项目名>.pages.dev。但既然我们第1篇就把域名托管到Cloudflare了,这一步省了。」

绑定完成后,访问 https://spark-ai.com 就能打开你的网站了。spark-ai.pages.dev 也依然可用。

八、Pages Functions:前端的"后花园"

「还有一个功能得提一嘴,」老张说。「你前面不是问了'没有后端怎么行'吗?Pages其实自带了一个轻量级的后端能力——Pages Functions。」

Pages Functions让你在项目中创建一个 functions/ 目录,放一些服务端代码,Pages会自动把它们部署为Serverless函数。本质上它就是Cloudflare Workers——跑在边缘网络上的JavaScript运行时。

「比如你想做一个简单的API接口,或者处理表单提交,不用单独搭后端,在Pages项目里写几个Functions就行。」

老张在白板上写了个简单示例:

// functions/api/hello.js
export async function onRequest(context) {
return new Response(JSON.stringify({ message: "Hello from 星火AI!" }), {
headers: { "Content-Type": "application/json" },
});
}

部署后访问 https://spark-ai.com/api/hello 就能拿到JSON响应。

「不过Functions的能力有限,复杂业务逻辑还是需要独立的Workers。」老张说,「这个等下一篇讲Workers的时候详细聊。你现在只要知道Pages不只是能放静态文件,还能跑一点点后端代码就够了。」


小结

林一看着浏览器里 https://spark-ai.com 打开的星火AI首页,回味着今天学到的内容。

「总结一下,」老张说,「你今天完成了几件事:」

  1. 理解了JAMstack架构——静态内容走CDN,动态数据走API,前后端分离,各司其职。
  2. 用Pages部署了前端——连接GitHub仓库,push代码自动构建自动部署,全程不用碰服务器。
  3. 搞定了预览部署——每个PR自动生成预览环境,团队协作效率拉满。
  4. 绑定了自定义域名——spark-ai.com 正式上线,HTTPS自动配置。
  5. 知道了Pages Functions——轻量级后端能力,后续Workers篇会深入。

「记住,Pages的核心价值不是'免费托管静态文件'——这事儿很多平台都能干。它的核心价值是把部署流程做到了极致简单:Git集成、自动构建、预览部署、全球CDN,一条龙服务,你只管写代码。」

林一点点头,然后突然想起了什么:「张哥,那后端API呢?星火AI的智能问答功能,前端调的API从哪来?」

老张站起身,拍了拍裤子上的灰:「好问题。一个没有后端的网站,就像一家没有厨房的餐厅——门面再好看,顾客也吃不上饭。明天教你用Cloudflare Workers搭后端API,那才是真正的重头戏。」

本篇知识点回顾

知识点要点
静态网站 vs 动态网站静态=预制菜提前做好直接上菜;动态=现点现炒需要厨师
JAMstack架构J(JavaScript动态交互) + A(API后端服务) + M(Markup静态标记),前后端分离
Pages工作原理push代码→自动构建→生成静态文件→分发到全球CDN
Git集成支持GitHub和GitLab,授权后每次push自动触发构建
框架预设React/Vue/Next.js/Astro等20+框架预设,自动填构建命令和输出目录
构建命令框架提供的build命令(如 npm run build),无框架留空
构建输出目录构建产物所在目录(如 dist/public/build),按框架而定
环境变量构建时注入,系统变量含 CF_PAGES_BRANCHCF_PAGES_COMMIT_SHA
预览部署非生产分支自动生成预览URL(hash+分支别名),默认带noindex
分支别名branch-name.pages.dev 形式,始终指向该分支最新部署
预览访问控制通过Cloudflare Access限制预览环境访问权限
自定义域名项目→Custom domains→输入域名,DNS在CF上则自动配置CNAME和证书
Pages Functionsfunctions/目录下的代码自动部署为Serverless函数,本质是Workers
构建坑:Node版本通过 NODE_VERSION 环境变量指定Node.js版本
构建坑:大小写Linux区分文件名大小写,macOS不区分,注意import路径
构建坑:输出目录目录写错会导致部署成功但页面404

动手挑战

  1. 基础题:把一个前端项目(React/Vue/纯HTML都行)部署到Cloudflare Pages,确保能通过 *.pages.dev 域名访问。

  2. 进阶题:创建一个新分支修改页面内容,push后查看预览部署URL,在GitHub PR页面找到Cloudflare自动评论的预览链接。然后合并PR到main分支,观察生产环境自动更新。

  3. 思考题:你的项目同时需要开发环境和生产环境不同的API地址。如何利用Pages的环境变量和系统变量 CF_PAGES_BRANCH,让构建时自动选择正确的API地址?(提示:可以在构建脚本中根据分支名判断,也可以在Pages后台为Production和Preview分别配置不同的环境变量)

下回预告

星火AI的页面终于上线了,林一兴冲冲地发给小王看。小王回了一句:「页面挺好看的,但智能问答功能怎么用不了?点了按钮没反应啊。」

林一一看控制台,满屏的红色错误:API request failed — 404 Not Found

「废话,」老张在旁边说,「你前端调的 /api/chat 接口根本不存在。一个没有后端的网站就像没有厨房的餐厅——门面再好看,顾客也吃不上饭。明天教你用Cloudflare Workers搭后端API,让你的星火AI真正'亮'起来。」

「Workers又是什么?」

「Serverless。边缘计算。你的代码跑在全球330个城市的节点上,离用户最近的那个响应请求。还是免费的。」

林一的眼睛又亮了。


本文是《林一的 Cloudflare 通关记》系列第4篇。 上一篇:给网站请个超级快递员——CDN加速与缓存策略 下一篇:网站要有个"厨房"——Cloudflare Workers搭建后端API

wp