MadeMe
回到所有文章
PERSONAL JOURNAL

用 Astro、BlockNote 和 Cloudflare 搭建个人写作网站

MMadeMe·

这套网站把写作后台和文章阅读放在一个项目里。可以在浏览器中编辑正文、上传图片、保存草稿,还有进行发布。

页面和接口由 Astro 组织,交互界面使用 React,编辑器采用 BlockNote。部署时,把应用交给 Cloudflare Workers,文章数据放进 D1,图片和附件放进 R2。

下面按网站结构、开源组件和部署过程,把这套组合讲清楚。

1. 网站的整体结构

读者打开文章时,Astro 从数据库读取已发布的内容,在服务端生成页面。作者进入写作界面时,浏览器加载 React 和 BlockNote,提供编辑、上传和发布操作。

flowchart TD
    Reader[读者浏览器] --> App[Cloudflare Workers<br/>Astro 页面与接口]
    Author[作者浏览器] --> App
    App --> Assets[前端静态资源]
    App --> Database[D1<br/>文章、设置等数据]
    App --> Media[R2<br/>图片与附件]
    App --> AI[外部模型服务<br/>写作与配图]

页面渲染、数据读写和权限处理都在同一个应用中完成。Cloudflare 适配器负责把 Astro 项目接到 Workers 上,前端脚本和样式随应用一起发布。

这种结构适合个人写作网站:日常维护主要围绕应用代码、文章数据和媒体文件展开,服务器进程与底层运行环境由平台管理。

2. 开源组件各负责什么

组件在项目中的用途
Astro组织页面、路由、服务端渲染和接口
React编写编辑器、媒体库和设置页等交互界面
BlockNote提供块编辑器,支持段落、标题、列表、表格和媒体内容
Mantine提供编辑器等界面使用的 React 组件
TypeScript为代码提供类型约束
Zod校验接口输入和业务数据
Drizzle声明数据库结构,配合工具生成迁移文件
Lucide提供界面图标
jose处理 Google 登录所需的身份令牌验证
Wrangler管理 Cloudflare 资源、执行迁移和部署应用

这里最影响使用体验的两个组件是 Astro 和 BlockNote。Astro 负责把网站各部分组织起来,BlockNote 提供写作时直接接触到的编辑能力。

BlockNote 基于 Tiptap 和 ProseMirror,项目在它的基础上接入图片上传、文章保存、历史修订和发布操作。前台原地编辑与后台写作可以共用一套编辑器。

Drizzle 用于定义表结构和生成迁移文件,实际业务查询通过 D1 的参数化 SQL 完成。这样,数据结构的变化可以跟随代码一起维护。

3. 文章和图片怎样保存

草稿与发布内容分开保存

文章正文以块数据存入 D1,标题、分类、标签和站点设置也保存在数据库中。Markdown 用于内容的导入和导出。

保存草稿后,作者可以继续修改;点击发布后,系统才更新读者看到的内容。例如,一篇文章已经发布,作者又改了标题,保存后的新标题先留在后台,等再次发布时才对读者生效。

编辑器还会处理并发修改带来的冲突,让作者保留当前输入,再决定怎样处理另一份改动。

图片和附件放在 R2

图片上传后,文件本身存入 R2,文件记录保存在 D1。文章引用这些记录来展示图片、视频和附件。

文件访问经过应用处理,并遵循文章的访问权限。部署时,R2 存储桶保持私有,由 Worker 读取其中的文件。

AI 功能通过服务端接入

AI 写作和配图由 Worker 调用外部模型服务。编辑器把操作提交给服务端,再展示返回的建议;作者确认应用后,建议才进入当前稿件。

模型凭据保存在服务端运行环境中,网站设置页负责选择模型和调整提示词。

4. 部署需要哪些 Cloudflare 资源

核心资源包括一个 Worker、一个 D1 数据库和一个 R2 存储桶。

资源负责的内容
Workers执行页面渲染、接口和权限逻辑
D1保存文章、站点设置、媒体记录等数据
R2保存图片、音视频和附件
静态资源托管提供前端脚本、样式和站点静态文件

Cloudflare 管理应用运行和存储资源。项目代码通过资源绑定使用数据库与存储桶,部署时把两边关联起来即可。

使用 Sites 托管时,平台会按项目声明准备资源,并处理发布和访问控制。下面以自己的 Cloudflare 账户为例,介绍手动部署过程。

5. 部署到 Cloudflare

准备好 Cloudflare 账户、已启用的 Workers、D1 和 R2 服务,以及一份接入 Cloudflare 适配器的 Astro 项目源码。本地安装项目要求的 Node.js 和 npm,在项目根目录完成依赖安装:

npm ci

5.1 登录 Cloudflare

在项目根目录执行:

npx wrangler login
npx wrangler whoami

第一条命令会打开浏览器授权。第二条命令用于确认当前登录的账户,后续资源会创建在这个账户下。

5.2 创建数据库和媒体存储桶

下面使用通用示例名称,实际部署时可以自行替换:

npx wrangler d1 create my-blog-db
npx wrangler r2 bucket create my-blog-media

保存数据库创建后返回的标识,后面关联资源时会用到。已有对应资源时,可以继续使用原来的数据库和存储桶。

5.3 关联项目与资源

打开项目根目录的 Wrangler 配置文件,把新建的 D1 数据库和 R2 存储桶关联到应用,并沿用项目代码要求的绑定名称。

这里要配好三部分:Worker 的项目名称、数据库与存储桶的资源信息,以及正式环境需要的运行配置。静态资源和 Worker 入口由项目中的 Astro Cloudflare 适配器参与生成。

资源绑定也可以在 Cloudflare 控制台的 Worker 详情页管理。使用命令行持续部署时,同步维护项目配置,保证后续发布继续关联同一套资源。

5.4 初始化数据库

项目通过迁移文件建立表结构。先查看待执行的迁移,再应用到云端数据库:

npx wrangler d1 migrations list my-blog-db --remote --config wrangler.jsonc
npx wrangler d1 migrations apply my-blog-db --remote --config wrangler.jsonc

命令中的数据库名称与前面创建的资源保持一致,迁移目录沿用项目配置。已有文章数据时,先导出备份,再执行结构变更。

5.5 发布应用

在项目根目录生成部署文件,再上传到 Workers:

npm run build
npx wrangler deploy --config dist/server/wrangler.json

这里使用的是本项目生成的部署配置。发布完成后,可以在 Cloudflare 控制台查看 Worker、资源绑定和运行日志。

后续修改页面或功能时,重新执行这两条命令即可发布更新。数据库结构有变化时,先完成相应迁移。

5.6 配置作者登录和密钥

作者登录按项目支持的方式配置。这里以已有 Google 登录实现为例:在 Google Cloud 控制台创建 Web 类型的 OAuth 客户端,设置同意屏幕,并登记项目要求的登录回调。

然后在 Worker 的运行时设置中填写作者身份、OAuth 客户端信息和会话密钥。敏感值使用 Cloudflare Secrets 保存,源码中保留配置说明。

会话密钥可以在自己的终端生成:

openssl rand -hex 32

需要 AI 写作或配图时,同样把所选模型服务的凭据保存到 Secrets,再到网站设置页选择模型。

5.7 绑定自己的域名

域名接入 Cloudflare 后,在 Worker 的域名设置中添加自定义域名,按控制台提示完成关联。

使用自定义域名登录时,把网站来源和 Google 登录回调同步调整到这个域名,并使用 HTTPS。通过项目配置管理域名的,也同步更新配置文件,让后续命令行部署继续保留这项设置。

网站运行起来后,文章通过后台保存和发布,图片与附件进入 R2,站点程序通过 Workers 更新。日常维护时,保留原有数据库和存储桶,按内容变化与代码变化分别处理即可。