创建项目与品牌配置
创建 Saavo 项目,完成本地初始化、网站文案和主题颜色配置。
上一篇已经确定了产品范围和技术方案。这一篇创建正式的 Saavo 项目,完成本地运行、网站文案和主题颜色配置。
创建 WebpageToPDF 项目
原型验证完成后,就可以开始使用 Saavo 创建正式项目。
前面的原型阶段主要用来验证功能和方案是否可行。进入正式开发后,需要先准备好开发环境,再把已经验证过的功能逐步迁移到 Saavo 模板中。
这次教程使用 Windows,终端使用 PowerShell,开发工具使用 Cursor 和 Codex,后面的内容也都会基于这套环境来演示。
这只是我个人使用的工具组合,并不是 Saavo 的硬性要求。如果你已经有自己习惯的编辑器或 AI 编程工具,继续使用就可以,不需要为了跟着教程专门更换。
准备账号和基础环境
前面的准备工作已经介绍过具体步骤。如果你是直接从这篇实战教程开始看的,先确认下面几项:
- Saavo 账号和模板权限:先完成注册和购买。购买后,可以在账户中心的“我的产品”中看到 Saavo Starter。后面使用 CLI 授权时,也需要登录这个拥有模板权限的账号。
- Git:按照安装 Git完成安装,用来保存代码修改记录。后面让 AI 改代码时,也方便检查它具体改了什么。
- Node.js 和 npm:按照安装 Node.js完成安装。当前 CLI 和模板要求 Node.js 至少为
22.13.0,按准备工作里的步骤安装 Node.js 24 LTS 即可,npm 会一起安装。 - Cloudflare 账号:这个项目最终会部署到 Cloudflare,需要按照注册 Cloudflare完成注册、邮箱验证和 R2 开通。不过,只在本地运行 Saavo 模板时,还不需要远程资源,这一项可以在部署前补齐,也不用现在就手动创建数据库、Bucket 和队列。
安装完成后,重新打开 PowerShell,检查命令是否可用:
git --version
node -v
npm -v三条命令都应该输出版本号。如果提示找不到命令,先回到对应的安装文档处理。若 PowerShell 提示禁止执行 npm.ps1,参照 Node.js 安装页中的说明,可以先用 npm.cmd、npx.cmd 执行命令,不需要重新安装 Node.js。
域名、邮件、支付和第三方登录不需要一开始就全部配置好,域名我已经注册完毕: webpagetopdf.dev,但本地开发并不依赖域名。现阶段先把模板运行起来,等开发到邮件、付费和部署相关功能时,再配置对应的服务即可。具体可以参考可选服务中的内容。
安装 Cursor 和 Codex
如果你想使用和我一样的工具,还需要安装 Cursor 和 Codex。Cursor 主要用来查看和修改代码、运行终端命令,Codex 则用来分析项目、编写代码和排查问题。Cursor 其实也提供 AI 功能,实际开发时用哪个工具完成任务,按自己的习惯来就可以。
- Cursor:打开 Cursor 下载页,选择适合自己系统的桌面版并安装。第一次启动时,按提示完成账号登录和基本设置,是否导入其他编辑器的配置,可以自行决定。
- Codex:这里使用桌面端,按 OpenAI 官方桌面端安装说明下载并安装,Windows 用户可以直接看 Windows 安装页。安装后用自己的 ChatGPT 账号登录,按提示完成初次设置。后面需要让它打开本地项目目录,而不只是把代码复制到聊天窗口里。
这两个工具的账号和 Saavo 账号是分开的,安装完成后,先确认自己要用的 AI 功能可以正常使用,可用模型和额度以各自账号里显示的内容为准。
创建并初始化项目
打开 PowerShell/CMD,进入准备存放项目的上级目录,再执行:
npx saavo-cli@latest create webpagetopdf这条命令会在当前目录下创建一个 webpagetopdf 文件夹。如果前面的原型项目已经使用了这个名字,换一个目录即可,避免覆盖原来的代码。
第一次运行时,npx 可能会提示安装 saavo-cli,确认安装后继续即可,不需要提前全局安装 CLI。
接下来会打开 Saavo 的浏览器授权页面。登录拥有模板权限的账号,确认授权内容后允许访问,再回到终端。如果账号下有多个可用模板,按提示选择这次使用的模板即可。
模板下载完成后,CLI 会询问是否准备本地开发环境:
Prepare the project for local development?
Installs dependencies, creates .env, and initializes local databases.这里选择 Yes。CLI 会安装依赖,再调用模板中的 saavo:init,创建本地 .env、生成 SAAS_SECRET 和 Cloudflare 类型、初始化本地 D1 数据库,最后运行 doctor 检查配置。这些步骤不需要自己再做一遍,Wrangler 也会随项目依赖一起安装。
等终端显示 Project is ready for local development,说明本地初始化已经完成。如果跳过了初始化,或者依赖安装、初始化中途失败,先解决终端提示的问题,再进入已经下载好的项目目录补做:
cd webpagetopdf
npm install
npm run saavo:init完整的授权和初始化截图可以参考创建项目。
打开项目,确认能正常运行
在 Cursor 中打开整个 webpagetopdf 文件夹,不要只打开单个文件。然后在 Codex 中添加本地项目,同样选择这个文件夹。打开后,根目录下应该能看到 package.json、config/、src/ 和 AGENTS.md。

模板已经内置了 AGENTS.md 和 .cursor/rules/ 中的项目规则,使用 AI 修改代码时不要删除这些文件。Cursor 和 Codex 可以同时打开同一个项目,但尽量不要同时修改同一批文件,避免出现内容被覆盖的情况。
在 Cursor 的终端中确认当前目录是 webpagetopdf,然后运行:
npm run dev用浏览器打开终端中显示的本地地址,先确认首页、文档、登录和注册页面都能正常访问。

这时看到的应该还是 Saavo 的默认页面,先不要急着迁移原型代码。如果模板本身存在报错,先按照本地运行中的说明完成排查,确认基础环境正常后再继续开发。
此时,初始化脚本已经生成了 .env 文件。里面包含的密钥不要提交到 Git,也不要直接复制到其他项目中使用。
模板在本地开发时会使用本地运行时模拟数据库和存储。邮件、Stripe、第三方登录等外部服务暂时不需要配置,等开发到对应功能时再填写相关凭据。
页面能够正常打开,只代表项目已经在本地成功运行,并不表示这些外部服务已经配置完成。
更改网站文案信息
初始化模板之后,先不用管主题样式,也不用管页面内容,首要任务是确认网站的三要素:域名、标题和描述。
domain: webpagetopdf.dev
title: Webpage to PDF
description: Convert a URL to PDF online. Capture full webpages, customize PDF layouts, and hide unwanted content with a visual editor before exporting.接下来不需要手动修改,只需要在 Codex 中执行项目自带的 Agent 即可完成内容初始化,提示词如下:
使用以下参数执行 $saavo-initialize-content:
{
"domain": "webpagetopdf.dev",
"title": "Webpage to PDF",
"description": "Convert a URL to PDF online. Capture full webpages, customize PDF layouts, and hide unwanted content with a visual editor before exporting."
}执行完成后,再打开 config/base.ts 文件,确认里面的内容已经更新为:
export const websiteBaseCfg = {
siteName: {
value: "Webpage to PDF",
key: 'website.title',
},
siteDescription: {
value: "Convert a URL to PDF online. Capture full webpages, customize PDF layouts, and hide unwanted content with a visual editor before exporting.",
key: 'website.description',
},
siteOGImage: '',
siteOGImageAlt: '',
siteOGImageWidth: 1200,
siteOGImageHeight: 630,
twitterSite: '',
twitterCreator: '',
twitterImage: '',
fbAppId: '',
// 精确匹配的允许列表。应用验证该地址后才授予管理员角色。
// 这些值有意不进行邮箱别名匹配。
adminEmails: ['admin@saavo.dev'],
supportEmail: 'support@saavo.dev',
fromEmailAddress: {
name: "Webpage to PDF",
email: 'send@mail.saavo.dev',
},
}顺手把邮箱配置也更新一下:
export const websiteBaseCfg = {
...
adminEmails: ['admin@webpagetopdf.dev'],
supportEmail: 'support@webpagetopdf.dev',
fromEmailAddress: {
name: "Webpage to PDF",
email: 'send@mail.webpagetopdf.dev',
},
}接下来最好在 Codex 中再检查一遍,避免 Agent 执行过程中存在遗漏:
根据上面的 Webpage to PDF 产品说明,独立检查网站,直接修正已经确认的遗漏、旧品牌内容、不一致的文案、翻译问题和意外修改。不要依赖之前的报告,也不要调用初始化技能。避免无关修改,执行相关检查,并简要说明已修正的内容和剩余问题。确认无误后,重新运行 npm run dev 确认网站信息已经更新。

调整主题颜色
运行上面的初始化 Agent 后,网页中的文案已经更改为新的内容,但是主题颜色还是默认的,接下来我们调整一下主题颜色。
主题颜色只需要调整项目中的 styles/base.css 文件,不需要手动逐项修改,直接让 Codex 处理即可。
找到之前的原型项目,让 Codex 按照固定格式提取调色盘信息:
提取当前原型的配色,填入下方 CSS 模板。
要求:
1. 优先使用源代码中的实际颜色。如果只有截图,则从截图提取颜色。保留原型的品牌特征和视觉风格。
2. 如果原型没有深色主题,创建中性的炭灰色主题。背景、卡片和侧边栏保持中性色,品牌色主要用于按钮和强调元素。
3. 计算对比度:普通文字(包括次要文字)与其背景的对比度至少为 4.5:1。必要的控件边界和焦点指示器与相邻颜色的对比度至少为 3:1,必要时调整颜色。
4. 只替换 <HEX> 和 <SHADOW>。保留选择器、变量名、顺序、分组及其他所有设置。使用小写六位 HEX 颜色,阴影颜色使用 rgb(R G B / A)。
5. 只输出完整的 CSS。不要遗漏变量、保留占位符或修改项目文件。
:root {
color-scheme: light;
--radius: 0.75rem;
--background: <HEX>;
--foreground: <HEX>;
--card: <HEX>;
--card-foreground: <HEX>;
--popover: <HEX>;
--popover-foreground: <HEX>;
--primary: <HEX>;
--primary-foreground: <HEX>;
--secondary: <HEX>;
--secondary-foreground: <HEX>;
--muted: <HEX>;
--muted-foreground: <HEX>;
--accent: <HEX>;
--accent-foreground: <HEX>;
--destructive: <HEX>;
--destructive-foreground: <HEX>;
--border: <HEX>;
--input: <HEX>;
--ring: <HEX>;
--brand-primary: <HEX>;
--brand-primary-strong: <HEX>;
--brand-warm: <HEX>;
--brand-success: <HEX>;
--brand-danger: <HEX>;
--brand-info: <HEX>;
--brand-from: <HEX>;
--brand-to: <HEX>;
--chart-1: <HEX>;
--chart-2: <HEX>;
--chart-3: <HEX>;
--chart-4: <HEX>;
--chart-5: <HEX>;
--sidebar: <HEX>;
--sidebar-foreground: <HEX>;
--sidebar-primary: <HEX>;
--sidebar-primary-foreground: <HEX>;
--sidebar-accent: <HEX>;
--sidebar-accent-foreground: <HEX>;
--sidebar-border: <HEX>;
--sidebar-ring: <HEX>;
--shadow-xs-value: <SHADOW>;
--shadow-sm-value: <SHADOW>;
--shadow-md-value: <SHADOW>;
--shadow-lg-value: <SHADOW>;
}
.dark {
color-scheme: dark;
--background: <HEX>;
--foreground: <HEX>;
--card: <HEX>;
--card-foreground: <HEX>;
--popover: <HEX>;
--popover-foreground: <HEX>;
--primary: <HEX>;
--primary-foreground: <HEX>;
--secondary: <HEX>;
--secondary-foreground: <HEX>;
--muted: <HEX>;
--muted-foreground: <HEX>;
--accent: <HEX>;
--accent-foreground: <HEX>;
--destructive: <HEX>;
--destructive-foreground: <HEX>;
--border: <HEX>;
--input: <HEX>;
--ring: <HEX>;
--brand-primary: <HEX>;
--brand-primary-strong: <HEX>;
--brand-warm: <HEX>;
--brand-success: <HEX>;
--brand-danger: <HEX>;
--brand-info: <HEX>;
--brand-from: <HEX>;
--brand-to: <HEX>;
--chart-1: <HEX>;
--chart-2: <HEX>;
--chart-3: <HEX>;
--chart-4: <HEX>;
--chart-5: <HEX>;
--sidebar: <HEX>;
--sidebar-foreground: <HEX>;
--sidebar-primary: <HEX>;
--sidebar-primary-foreground: <HEX>;
--sidebar-accent: <HEX>;
--sidebar-accent-foreground: <HEX>;
--sidebar-border: <HEX>;
--sidebar-ring: <HEX>;
--shadow-xs-value: <SHADOW>;
--shadow-sm-value: <SHADOW>;
--shadow-md-value: <SHADOW>;
--shadow-lg-value: <SHADOW>;
}然后将提取到的信息填入到 styles/base.css 文件中即可。

本篇检查
完成这一篇后,应能在本地打开项目,并确认网站文案、邮箱配置和主题颜色已经更新。