使用 Cloudflare Pages 部署静态网站

2022-07-06 · 1,766 chars · 9 min read

2021 年年底的时候,我通过 web archive 找回了所有网站页面,重新整理并使用 react + SSG 的方式,搭建了当前这个站点。最开始的时候是部署在 vercel 上的,整体用起来还是很方便的,但是访问速度比较尴尬,按照 vercel 官方的说明改了 DNS 解析,结果我测试发现,国内无代理可以直接访问,但是香港却不行...

虽然没有做太多实测,但是目前网上的普遍观点是,vercel 之类的小厂不太稳定,而 Github Page 国内很慢,Cloudflare 国内也一言难尽,但是整体功能性上占优。考虑了一段时间,决定还是切换到 Cloudflare Pages,希望尽可能兼顾所有用户,外加能访问到我网站的朋友,应该大部分都是码农,代理加持下速度不会太差。

最直接的使用方式#

Cloudflare Pages 提供了三种方式创建项目:

  • 链接到 Git:支持 Github、GItlab
  • 直接上传
  • 使用 wrangler cli:支持其它的代码托管平台和 CI

我最开始用的就是直接关联 Github,创建方法非常简单就不细说了,按照它网站上的步骤一步一步来就行了。

创建好项目之后,可以对项目进行一些设置:

大体上就是:

  • 自定义域名:除了默认的 :project.pages.dev 之外,可以添加自己的域名(要先使用 Cloudflare 的 DNS)
  • 设置
    • 常规设置:修改名称、添加成员、开启 Web Analytics 等
    • 构建和部署:控制部署的分支,命令,环境等等
    • 环境变量:添加环境变量,例如 node 版本就是通过 NODE_VERSION 设置的
    • 函数:SSG 的静态页面,还没用过

当你设置的分支有新提交,Cloudflare Pages 就会自动触发构建和部署

你可以控制的只有两处

  • 构建命令:使用什么命令构建,如 npm run build
  • 文件目录:构建完的产物在哪个目录下,如 publicdist

然后就没有然后了,能覆盖大部分“前端静态应用”的需求了。但是......

使用 Github Actions 和 wrangler#

上面讲的方式虽然简单,但是还是存在一些问题的。

首先,我想用 pnpm,我还是比较认同 pnpm 的理念的,外加 npm 又十分拉跨,导致我十分想试试 pnpm。可是上述方式会自动的执行 npm install,目前没得选,虽然在 build 命令里安装 pnpm 在理论上是可行的,但是却非常不“纯粹”,逼死强迫症。

其次,我用 Github Action 执行一整套 CI 操作,包括 lint、build 等,前面讲的方式,在部署的时候会 build 两次,一次在 github 一次在 cloudflare,再次逼死强迫症。

第三,构建部署和 Github Action 是同步执行的,没什么关联关系。但理想的方式肯定是等 CI 全部通过后再执行部署。

所以最佳的部署流程是,在 Github Action 里执行完所有 CI 的验证,包括 build。然后直接使用 build 的产物部署到 Cloudflare Pages。刚好,Cloudflare 提供了 wrangler 工具可以帮我们完成理想的构建流程。

wrangler 提供了官方的 action,用它来部署仅需两个 token

on: [push]

jobs:
  deploy:
    runs-on: ubuntu-latest
    name: Deploy
    steps:
      - uses: actions/checkout@v3
      - name: Publish
        uses: cloudflare/[email protected]
        with:
          apiToken: ${{ secrets.CF_API_TOKEN }}
          accountId: ${{ secrets.CF_ACCOUNT_ID }}
          command: pages publish --project-name=example
  • CF_API_TOKEN:要自己创建,点进个人资料,找到 API 令牌创建即可
  • CF_ACCOUNT_ID:这个在 dashboard-网站-概述 的右下角可以直接看到

将这两个 token 添加到 github secrets 里即可。最后按照实际需求修改 publish 命令

pages publish [DIRECTORY] --branch=main --project-name=example

特别说明下,我是使用直接上传的方式创建了一个新项目(实际上可能用 cli 更好?),他默认的生产分支是 main,必须指定分支,否则全部部署到预览环境里。

至此,大功告成。

一些细节问题#

在使用过程中还是发现不少问题的,整体的感觉就是产品尚在初级阶段,存在不少不完善不合理的地方。

不支持 html 后缀#

这个问题非常尴尬,真的是不用不知道。具体表现是访问一个以 .html 为后缀的 url 时,会被自动重定向到不含 .html 的地址。例如访问 https://keenwon.com/rem-layout.html 时会自动 308 重定向到 https://keenwon.com/rem-layout

也许,也许吧,.html 后缀真的没什么用,Cloudflare 也是这么想的,外加 308 重定向了,目前看对 SEO 的影响不大,但就是非常别扭。而我的网站,正常的 SPA 路由跳转没任何问题,刷新或者直接进入具体页面,就 404 了,用过前端路由的都懂。

目前这个问题我选择忍了,代码也改了。在排查的过程中也发现它的官方文档里写了:

If an HTML file is found with a matching path to the current route requested, Pages will serve it. Pages will also redirect HTML pages to their extension-less counterparts: for instance, /contact.html will be redirected to /contact, and /about/index.html will be redirected to /about/.

官方的社区里也有很多人反馈这个问题,不知道后续会不会解决。

_headers#

Cloudflare Pages 其实就是用来发布静态网站的(不算 workers 等),仅有少量动态功能,比如设置重定向和自定义标头。其中自定义标头,可以在项目根目录添加 _headers 文件设置。

上文提到过,Cloudflare Pages 会有一个 .pages.dev 的默认域名,且删除不掉。另外每次部署也有预览域名,大概长这样 https://45cxxxxxx.keenwon.pages.dev/,我不希望这些域名影响 SEO,所以可以用 _headers 告诉搜索引擎不要索引

https://keenwon.pages.dev/*
  X-Robots-Tag: noindex

预览域名默认有 noindex,只要把 .pages.dev 默认域名加上即可。

_headers 存在一个 bug 就是即使实测生效了,但是在 dashboard 里面还是看不到,永远显示一个示例,这是一个已知的 bug。

还有一个比较奇怪的设计就是,文档明明写的是创建一个 _headers 文件在项目输出的文件夹里

To attach headers to Cloudflare Pages responses, create a _headers plain text file in the output folder of your project. It is usually the folder that contains the deploy-ready HTML files and assets generated by the build, such as favicons.

但是使用 wrangler 发布的时候,却是通过 formdata 提交的,并未上传并展示在文件清单里(issues)。这个问题上面也耽误了不少时间。

最后#

Cloudflare Pages 整体上感觉还是可以,基本该有的功能都有了,虽然还是发现一些 bug,一些设计上的缺陷,但瑕不掩瑜。

而且它不仅仅是托管静态页面,配合 Cloudflare Workers 和 R2,可以方便的构建全栈应用,有兴趣的朋友可以去了解下。

参考:

赞赏

微信