Cloudflare Workers 在开挖 Tunnels(误)

将 Cloudflare Pages 迁移到 Workers

最近 Cloudflare 宣布 Workers Static Assets 进入“普遍可用”阶段,并在博客里建议新应用都使用 Workers 而非传统的 Pages1

词元的博客一直都是托管在 Pages 上的,之前就想实现 UA 分流,例如 cURL 访问就返回纯文字版本,浏览器访问就返回网页版,但是在纯静态的情况下基本不可能实现2。既然 Cloudflare 把 Workers 吹上天了,那就来试试到底有多神奇吧 🔥

🤔 等等!

Pages 是静态资源托管,访问次数和流量都是无限的;Workers 则需要执行用户脚本,免费版本每天限制调用 100,000 次。虽然看着很多,实际上也用不完,但是考虑每一个请求都需要计入,是不是有点浪费?

确实 😭 词元还有很多其他的 Workers,共享十万次请求,着实有点害怕(serverless 都能被 DDoS 到下线 😅)。但是考虑到 Workers 广阔的开发空间,以及 Cloudflare 的承诺“新功能都给 Workers”,词元决定玩一下,把博客转移到 Workers。

就算哪天发现不好用或者出事儿了,迁移回来也很方便嘛 😇

⛅ Wrangler

Wrangler 是 Cloudflare 提供的 Workers 开发工具,可以快速构建项目初始设置,还能在本地模拟运行一个 Workers 实例;总之就是我们必须要用。

Wrangler 基于(万恶的)Node.js 开发,所以您得先装个 Node.js 和 npm。然后,找一个风水宝地,执行:

1
npm create cloudflare@latest -- bug-barrel

嗯,词元决定将博客的名字还是改回原来的“桶装幺蛾子”,因为谷歌上“词元计数器”就算全文匹配都搜不到自己的博客 🤣

在接下来的几个选择中,我们分别选中“Hello World Example”“Worker only”和“JavaScript”,当然语言您可以选择自己的喜欢的,不过注意 Python 只支持 PSL 里的库。

Wrangler 安装第一步

Wrangler 安装第二步

暂不部署

稍等 Wrangler 初始化项目并安装依赖,然后选择启用 git,并且暂时不部署你的应用3,然后切换到项目目录里,你应该会看到这样的一些文件:

1
2
./   .editorconfig  .gitignore     package.json       .prettierrc  test/             .vscode/
../  .git/          node_modules/  package-lock.json  src/         vitest.config.js  wrangler.jsonc

这里面大部分都是测试文件,我们暂时不做开发,所以先删除:

1
rm -rf .editorconfig .prettierrc test .vscode vitest.config.js

然后看看 src 这个目录,里面就有我们需要的 index.js,也就是客户端访问网站的时候,Cloudflare 服务器执行的用户脚本。另外一个重要的文件就是 wrangler.jsonc,词元更喜欢 TOML,所以可以直接改成 wrangler.toml。词元做了以下配置(就是对您现在看到的博客!):

1
2
3
4
5
6
7
8
name = "bug-barrel"
main = "worker/index.js"
compatibility_date = "2025-01-01"

[assets]
directory = "./pub"
binding = "PAGES"
not_found_handling = "404-page"

很简单吧,主要修改的有几个:

  • index.js 挪到 worker 目录下,因为这个 src 名不副实。
  • 设置了静态文件目录绑定,之后就可以在脚本里用 PAGES 访问静态文件目录。

然后您可以创建一个 pub 目录,待会儿我们会把 Hugo 生成的文件放进去。然后我们来编辑 worker/index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Just a simple redirect from /something to /web/something
// Expect to bring plain-text version in the future, and return by UA


export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    url.pathname = `/web${url.pathname}`;
    const modifiedRequest = new Request(url.href, request);
    return env.PAGES.fetch(modifiedRequest);
  },
};

也非常简单,因为词元目前还没有实现前面说的纯文字版本,就把所有的请求都重定向到 /web 里。

Wrangler 的部分就到这里结束,接下来说说 Hugo 的集成。

🚘 Hugo

Hugo 是用 Go 语言编写的,而且完全是静态的,所以自然就没有官方的框架支持。但是,npm 有一个打包好的 Hugo,我们可以直接安装:

1
npm install --savedev hugo-bin

注意不是 hugo,这名字被一个不相干的项目给占掉了。

然后我们就可以通过 npm hugo 来调用 Hugo 生成页面了。为了方便,我们可以在 package.json 里添加一条:

1
2
3
4
5
{
    "scripts": {
        "build:hugo": "hugo --source ./src --destination ../pub/web"
    }
}

这里,词元打算把源文件全放进 src 目录,而生成的文件在 pub/web。奇怪的是 Hugo 似乎认为 pub/web 是相对于 src 来说的,所以还得加个 ..

Hugo 的使用和配置不是这则博客的重点,大家可以看看 Hugo 文档自己配置,或者到桶装幺蛾子仓库去看看词元定制的 CratMod 主题(修改自著名的 PaperMod)。

这样,src 里就是一个完整的 Hugo 站点,不需要做任何特殊调整。

我们可以再写一个脚本 worker/build.sh,自动化构建流程:

1
2
3
4
5
6
7
8
#!/bin/bash

mkdir pub

# Use Hugo to generate web version
npm run build:hugo

# Maybe going to add a cURL version in the future...

🧑‍🏭 组装测试

现在我们大部分的工作都已经完成了,在 commit 之前一定要记得在 .gitignore 里添加一下 Hugo 的忽略列表:

1
2
3
4
# Hugo-generated static files

.hugo_build.lock
pub

构建并本地运行,测试一下:

1
2
bash worker/build.sh
npx wrangler dev

按下 b 键就可以在浏览器里查看你的运行情况。

Wrangler 启动了本地服务器

然后,就可以登录 Wrangler,用 Cloudflare 账号授权:

1
npx wrangler login

并且把项目部署到 Cloudflare 上!

1
npx wrangler deploy

然后,为了实现自动部署,还得创建一个 GitHub 存储库,可以用 GitHub CLI,选择上传本地存储库:

1
gh repo create # 选择 Push an existing local repository to github.com

最后,我们需要到 Cloudflare Dashboard 网页端去操作,启用 Workers Build 并绑定我们的仓库:

启用 Workers Build

这些工作都结束之后,我们在仓库里提交随便一个 commit,就会触发构建,这和 Pages 的玩法就一样了。可以添加自己的自定义域名,然后尝试访问,应该没啥问题了。

🎆 下课!

当然这则博客是不完全的:没有利用 Workers 的很多功能,没有实现全套的纯文字版本构建。但是,咳咳,这就有待未来发展了 😁

🫟 2025 年 5 月 3 日更新:词元在当前版本的博客中移除了 Workers 脚本,在开发纯文本版本结束之前,避免浪费 Workers 次数。


  1. Your frontend, backend, and database — now in one Cloudflare Worker ↩︎

  2. 其实 Pages 有个 function 功能,但是既然都是算进 Workers 调用次数,为啥不直接用更好用的 Workers 呢对吧? ↩︎

  3. 因为在这里我们还没有登录,根据词元的实验,这里登录十有八九会失败,待会儿我们单独登录之后再部署到 Cloudflare 上。 ↩︎

Banner