本地开发与构建

按依赖、初始化、开发请求、内容生成和生产构建的顺序定位本地问题。

先区分问题发生在安装依赖、执行脚本、启动服务器,还是打开页面以后。服务器能监听端口,不代表配置加载、数据库访问和页面渲染都已经成功。

一、确认目录和运行环境

所有命令都在 CLI 创建的应用项目根目录执行,不是在 saavo-cli 或文档网站仓库执行。不同仓库的 package.json 不同,不能直接套用它们的部署命令。

node --version
npm --version

当前模板检查要求 Node.js 至少为 22.13.0,检查脚本建议使用 Node.js 24。更换版本后,重新打开终端,确认实际使用的版本已经切换。

如果看到 Missing script,先检查当前目录的 package.json。初始化源码包不包含模板维护者的 commit script,应用也没有默认的 deploy:prod script。完整列表见项目命令。

二、安装失败时保留锁文件

初次从发布源码包创建项目时可能没有 package-lock.json,使用:

npm install

如果已有有效且与 package.json 一致的锁文件,希望按锁定版本重新安装,可以使用 npm ci。该命令会重新安装依赖,锁文件不一致时会停止。

安装失败时先判断错误类别:

现象检查方向
网络超时、连接被拒绝包源、代理、网络访问情况
Node.js 版本不匹配当前终端版本,而不是只看已安装版本
文件被占用、访问被拒绝开发服务器、编辑器或其他进程是否正在使用文件
锁文件与依赖声明不一致是否有遗漏的依赖修改,确认后再更新锁文件
原生依赖或平台包加载失败是否从另一台机器复制了 node_modules,应在当前平台安装

不要把删除锁文件或执行强制依赖升级当作通用修复,这会同时改变许多依赖,难以判断原始问题是否解决。

三、补完本地初始化

依赖安装成功后执行:

npm run saavo:init

执行顺序是:

创建或保留 .env,补充缺失的 SAAS_SECRET
→ cf-typegen
→ db:migrate:local
→ doctor

该命令不会覆盖已有的有效主密钥,不会创建远程 Cloudflare 资源。如果在数据库步骤失败,前面的 .env 和类型文件可能已经生成。应修复当前错误后继续,不必删除整个项目重新创建。

初始化后 .env 中的第三方服务凭据仍可能为空。doctor 对 Stripe 或 OAuth 的提示不能直接解释成整个应用初始化失败,应先看最终错误数,再判断当前是否需要该服务。

如果 SAAS_SECRET 存在但格式错误,脚本不会替你随意更换。新项目应修正为有效配置,已有数据的项目应先找回原始密钥,不能直接覆盖。

四、开发服务器无法启动或打开页面返回 500

npm run dev

始终使用终端实际显示的地址和端口。项目会按开发服务器端口生成本地站点地址,不需要为了端口变化反复修改 .env 的 VITE_SITE_URL。

最早出现的错误处理方式验证结果
找不到模块完成依赖安装,确认没有复制其他平台的依赖目录原模块错误消失
配置启动校验失败按报错字段检查 config/ 及其引用能通过 npm run doctor 的配置加载
缺少 Binding核对 wrangler.jsonc,必要时运行 cf-typegen运行时能访问对应资源
no such table确认本地数据库并执行本地迁移同一页面不再报缺表
页面请求返回 500结合请求时间查看终端异常栈同一请求返回预期页面或业务响应

cf-typegen 只生成类型声明。编辑器不再报错,不等于运行时的 Binding 已经存在。也不要把 Cloudflare 资源访问临时替换成内存对象来隐藏配置问题。

本地 D1、KV 等状态与远程资源独立。删除 .wrangler 状态目录可能清空本地数据,排错前应先确认是否需要保留。

五、配置字段正确,但组合不成立

项目使用 TypeScript 与 Zod 两层检查。常见问题包括产品引用已删除的角色、联盟规则引用不存在的套餐、时间间隔格式不合法,以及把 LocalizedText 写成普通字符串。

先找到错误指向的配置项,再向它引用的对象查找。例如修改产品 ID 后,还要检查联盟推广、页面和升级建议是否继续使用旧 ID。不要用 as any 绕过校验。

字段类型和当前默认值见配置文件。前面的构建教程可能使用自成体系的示例名称,移植到自己的项目时需要统一引用,不能只复制一个配置片段。

六、文档、博客或搜索没有更新

内容更新涉及三个位置:源文件、构建生成的集合与搜索索引,以及运行时读取的 KV 内容。

npm run gen:collections

这一步用于检查 MDX 是否能编译。出现错误时,按文件名和行号检查 Frontmatter、未闭合的 JSX、代码围栏和组件属性。导航不显示时再核对 meta.json、语言目录和 deploy.content 开关。

需要更新搜索索引时运行:

npm run gen:search-index

如果当前问题是正文仍读取到旧的本地 KV 内容,再运行:

npm run kv:sync:local

以上操作用途不同,重新生成集合不会自动证明远程 KV 已更新。线上内容问题见部署、资源与域名。

七、开发正常,预览或构建失败

npm run preview

模板的预览命令会先执行 build:preview,再使用 127.0.0.1:4173 进行本地预览。预览经过打包流程,不能假定所有行为都与 npm run dev 相同,尤其是邮件发送、环境变量和仅在生产模式执行的检查。

需要单独定位检查阶段时运行:

npm run lint
npm run typecheck
npm run build

Vite 可以在不完成完整类型检查的情况下生成产物,构建成功不能代替 typecheck。修复代码后,用 npm run verify 完成项目全部检查。

以退出码和实际失败步骤判断结果。有些日志只是警告,但也不要因为最后看到了构建文件列表,就忽略前面出现的类型、内容生成或文件写入错误。

修复后的验证

重新启动项目,完成原来失败的页面操作。如果改动涉及内容,再分别检查导航、正文和搜索。如果改动涉及初始化,再确认原有本地账号和数据仍然可用,避免通过清空状态得到看似成功的结果。