- 数据库
- 后端
【免费下载链接】convex-backend
The open-source reactive database for app developers
导读
本文以开源仓库 convex-backend 中npm-packages/private-demos/tsgo-test演示项目为背景,完整讲解 Convex 函数(Functions)目录的标准组织方式:如何编写带参数校验(Validator)的 query 与 mutation 函数、如何在 React 客户端调用它们、如何通过 Convex CLI 将函数推送到部署环境,以及如何用 TypeScript 7 原生编译器 tsgo 对函数进行类型检查。读完本文,你将掌握一套可直接复制到任何 Convex 项目中的最小可运行函数代码骨架,并理解其背后 CLI 类型检查的实现原理。
一、Convex 函数目录是什么
在 Convex 应用中,服务端代码存放在项目的convex/目录中(即"函数目录")。这个目录里的每个 TypeScript/JavaScript 文件都会被打包并在 Convex 的云端或自托管后端中执行,构成应用的"服务端逻辑"。
以仓库中的npm-packages/private-demos/tsgo-test/convex/目录为例,其标准结构包含:
README.md:官方生成的函数目录说明模板(即本文依据的核心文档);example.ts:一个最小可运行的 query 函数示例;_generated/:由npx convex dev自动生成的类型与 API 绑定代码(api.ts、server.ts、dataModel.ts等);tsconfig.json:用于对 Convex 函数做类型检查的 TypeScript 工程配置。
_generated目录是自动生成、不应手工修改的。在 server.d.ts 文件头部明确写着:"THIS CODE IS AUTOMATICALLY GENERATED. To regenerate, runnpx convex dev.",其中导出了query、mutation、action、internalQuery、internalMutation、httpAction等全部服务端函数构造器,以及QueryCtx、MutationCtx、DatabaseReader、DatabaseWriter等上下文类型。这些类型化的导出正是下面所有函数示例的类型安全基础。
二、编写一个带参数校验的 query 函数
2.1 函数定义骨架
query 函数用于读取数据库,是 Convex 中默认"只读、可被客户端订阅"的函数。官方模板给出的标准写法如下(对应文档原文,可在 README.md 中查看):
// convex/myFunctions.ts import { query } from "./_generated/server"; import { v } from "convex/values"; export const myQueryFunction = query({ // Validators for arguments. args: { first: v.number(), second: v.string(), }, // Function implementation. handler: async (ctx, args) => { // Read the database as many times as you need here. const documents = await ctx.db.query("tablename").collect(); // Arguments passed from the client are properties of the args object. console.log(args.first, args.second); // Write arbitrary JavaScript here: filter, aggregate, build derived data, // remove non-public properties, or create new objects. return documents; }, });拆解这个骨架,有三个关键点:
args中的 Validator 是 Convex 的核心安全机制:v.number()、v.string()来自convex/values包,运行时会对客户端传入的每个参数做校验,类型不匹配的函数调用会被直接拒绝,从而避免"脏数据"进入数据库查询。除上述两种外,v还提供v.id()、v.object()、v.array()、v.union()、v.optional()等完整校验器集合,并支持.optional()链式写法。handler的第一个参数ctx是函数上下文:ctx.db提供数据库访问能力。对 query 而言,ctx.db的类型是只读的DatabaseReader(见 server.d.ts),只能get、query,无法写入。handler可以写任意 JS 逻辑:在返回前进行过滤、聚合、派生数据、剥离非公开字段等处理都是推荐做法——这相当于把"数据脱敏与业务加工"放在服务端完成。
2.2 最小可运行示例:仓库里的真实代码
上述模板是教学示例;仓库中tsgo-test演示项目实际部署了一个极简 query 函数,见 example.ts:
import { query } from "./_generated/server"; export const hello = query({ args: {}, handler: async (): Promise<string> => { return "Hello from TypeScript!"; }, });这个hello函数没有参数(args: {}),不做任何数据库访问,直接返回一个字符串。它虽然简单,却完整演示了 Convex 函数的最小闭环:定义 → 生成 API 绑定 → 被客户端调用。在生成产物 api.d.ts 中可以看到,api对象通过ApiFromModules自动收集了example模块下所有导出的函数引用,客户端即可通过api.example.hello类型安全地调用它。
2.3 在 React 中调用 query
Convex 为 React 提供了useQueryHook,模板中的用法如下:
const data = useQuery(api.myFunctions.myQueryFunction, { first: 10, second: "hello", });useQuery会自动完成三件事:订阅该查询、在数据变化时触发组件重新渲染、在组件卸载时取消订阅。它接收的参数对象与args中声明的 Validator 一一对应,类型由_generated/api.d.ts从函数定义中推导,因此参数写错会在编译期直接报错。
三、编写一个带参数校验的 mutation 函数
3.1 函数定义骨架
mutation 函数用于写入数据库(也可读取),并具备原子性保证。官方模板如下:
// convex/myFunctions.ts import { mutation } from "./_generated/server"; import { v } from "convex/values"; export const myMutationFunction = mutation({ // Validators for arguments. args: { first: v.string(), second: v.string(), }, // Function implementation. handler: async (ctx, args) => { // Insert or modify documents in the database here. // Mutations can also read from the database like queries. const message = { body: args.first, author: args.second }; const id = await ctx.db.insert("messages", message); // Optionally, return a value from your mutation. return await ctx.db.get("messages", id); }, });关键差异点:
ctx.db是读写类型DatabaseWriter:除get、query外还提供insert、patch、replace、delete等写操作;- 原子性保证:单个 mutation 内的所有写入会被原子地提交(见 server.d.ts 中
DatabaseWriter的文档注释),不会出现"写了一半"的中间状态,也天然规避了乐观并发控制下的部分写问题; - 可以返回值:
handler的返回值会被序列化后传回客户端,便于客户端拿到刚插入文档的_id做后续跳转或 UI 更新。
3.2 在 React 中调用 mutation
mutation 在 React 中通过useMutationHook 调用,模板给出了两种典型用法:
const mutation = useMutation(api.myFunctions.myMutationFunction); function handleButtonPress() { // fire and forget, the most common way to use mutations mutation({ first: "Hello!", second: "me" }); // OR // use the result once the mutation has completed mutation({ first: "Hello!", second: "me" }).then((result) => console.log(result), ); }- Fire-and-forget(推荐):多数 UI 场景下不关心返回值,直接调用即可,Convex 客户端会负责把结果同步到所有订阅相关查询的组件;
- 获取结果:
mutation(...)返回 Promise,.then()中拿到的正是服务端handler的返回值(如上面示例中插入后重新读回的完整文档)。
四、推送函数与 CLI 工具链
4.1 常用 CLI 命令
函数写好后,需要通过 Convex CLI 与部署环境交互。文档明确给出了两条基础命令:
- 查看 CLI 全部能力:在项目根目录运行
npx convex -h; - 启动本地文档:运行
npx convex docs会打开本地/在线的 Convex 文档站点。
实际开发中最常用的还有:
npx convex dev:本地开发模式,持续监听convex/目录,自动完成代码生成(_generated)与函数推送,并启动本地后端;npx convex deploy:将函数推送到生产部署;npx convex codegen --init:在缺少convex/tsconfig.json时创建类型检查所需的工程配置。
4.2 CLI 的类型检查实现
CLI 在每次推送前都会对函数目录执行 TypeScript 类型检查。仓库中的核心实现在 typecheck.ts:
- 编译器解析优先级(
resolveTypescriptCompiler,第33-39行):CLI 命令行参数 →convex.json中的typescriptCompiler字段 → 默认"tsc"; - 类型检查模式(
TypeCheckMode,第21行):enable(失败即中止推送)、try(找不到编译器时降级跳过)、disable(完全跳过,通过--typecheck=disable启用); - 检查入口:读取
convex/tsconfig.json,若不存在则跳过并提示运行npx convex codegen --init(第120-128行); - 慢检查提示:当单次类型检查超过 10 秒阈值(
SLOW_TYPECHECK_THRESHOLD_MS)时,CLI 会切换 spinner 并给出性能排查建议(第25-27行、第69-73行)。
4.3 使用 tsgo(TypeScript 7 原生编译器)
tsgo-test这个演示项目的特殊之处,正是用tsgo(TypeScript 原生编译器,即 TypeScript 7 的 Native Preview)替代传统tsc做类型检查。其配置链条如下:
①convex.json指定编译器(见 convex.json):
{ "typescriptCompiler": "tsgo", "$schema": "https://raw.githubusercontent.com/get-convex/convex-backend/refs/heads/main/npm-packages/convex/schemas/convex.schema.json" }②package.json声明 tsgo 依赖(见 package.json):
{ "name": "tsgo-test", "version": "0.0.0", "scripts": { "build": "tsgo --noEmit -p convex/tsconfig.json" }, "dependencies": { "convex": "workspace:*" }, "devDependencies": { "@typescript/native-preview": "~7.0.0-dev.20251205.1" } }这里@typescript/native-preview就是 tsgo 的 npm 发行包;build脚本直接以tsgo --noEmit -p convex/tsconfig.json方式对函数目录做纯类型检查(不产出文件),因此该脚本也可作为 CI 中独立于 Convex CLI 的类型检查步骤。仓库的 turbo.json 进一步注明该任务的outputs为空,即"只检查、无产物"。
③ CLI 如何定位 tsgo 可执行文件:在 typecheck.ts 的findTypeScriptCompilerPath中,tsgo会依次查找node_modules/@typescript/native-preview/bin/tsgo与bin/tsgo.js两个候选路径;tsc则会兼容 TypeScript 6/7 并存的场景,依次查找node_modules/@typescript/native/bin/tsc与node_modules/typescript/bin/tsc。若找不到编译器二进制,CLI 会以cantTypeCheck结果降级处理。
④ 版本兼容性注意:typescriptCompiler字段目前在convex.jsonschema 中已被标记为deprecated(见 convex.schema.json 与 CHANGELOG.md)。原因是 TypeScript 7 正式发布后,Convex CLI 会自动探测并选用原生编译器,无需再显式配置;但tsgo-test这类依赖 Native Preview 开发版的旧项目仍可通过该字段保持显式指定,两者兼容。
4.4 函数目录的 tsconfig.json 要点
convex/tsconfig.json描述了函数运行环境的 TypeScript 配置,其注释明确区分了"可修改"与"必需"两组选项(见 tsconfig.json):
- 可自由修改:
allowJs、strict、moduleResolution: "Bundler"、jsx、skipLibCheck、allowSyntheticDefaultImports; - Convex 必需(勿改):
target: "ESNext"、lib: ["ES2023", "dom"]、forceConsistentCasingInFileNames、module: "ESNext"、isolatedModules、noEmit; - include/exclude:
include: ["./**/*"]覆盖全部函数源码;exclude: ["./_generated"]排除自动生成目录,避免与手工源码重复检查。
五、从模板到生产:函数开发的最佳实践要点
综合官方模板(README.md)与仓库实现,可以把 Convex 函数开发的关键实践总结为以下几条:
- 始终为
args声明 Validator:这是客户端输入的第一道防线,也是客户端类型推导的数据源,空参数也应显式写args: {}(参考hello函数); - 查询逻辑尽量收敛到 query,写入逻辑收敛到 mutation:query 只读、可订阅、可被自动缓存,mutation 原子写入,二者职责分离能让 UI 保持实时一致;
- 服务端完成数据加工:过滤敏感字段、聚合、派生计算放在 handler 中,而不是让客户端拿到全量数据;
- 把
convex/下的 README 模板当作速查手册:模板中 query/mutation 的完整骨架、React 调用示例、CLI 命令提示,覆盖了 80% 的日常开发场景; - 用 tsgo/tsc 做独立类型检查:可将
tsgo --noEmit -p convex/tsconfig.json(或tsc等价命令)接入 CI,与npx convex deploy内置的类型检查形成双保险。
六、参考资料
- 官方函数目录模板:README.md
- 最小 query 函数实现:example.ts
- 自动生成的类型绑定:server.d.ts、api.d.ts
- 编译器与工程配置:convex.json、tsconfig.json、package.json
- CLI 类型检查实现:typecheck.ts
typescriptCompiler配置项 schema:convex.schema.json
- 数据库
- 后端
【免费下载链接】convex-backend
The open-source reactive database for app developers
相关推荐
编写 Convex 函数:从 query 到 mutation 的完整实战指南(基于 convex-backend 开源仓库)
编写 Convex 函数:从 query 到 mutation 的完整实战指南(基于 convex backend 开源仓库) 导读 本文围绕 convex b
数据库后端Convex 函数开发实战指南:在 Next.js 中编写 Query 与 Mutation(基于 convex-backend 源码解析)
Convex 函数开发实战指南:在 Next.js 中编写 Query 与 Mutation(基于 convex backend 源码解析) 本文以 conve
数据库后端Convex 函数开发实战:在 TanStack Start + WorkOS 示例项目中编写 Query、Mutation 与 Action
Convex 函数开发实战:在 TanStack Start + WorkOS 示例项目中编写 Query、Mutation 与 Action 本文以开源仓库
数据库后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考