其他
创建、组织和发布自包含可复用 Convex…
适用于基于 Convex 构建可跨项目复用的组件包,并正确配置 schema、函数、hooks、导出和 npm 发布。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 35/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 40/100 ×0.15
适用场景
创建、组织和发布自包含可复用 Conve特定
解决思路
- 实现前不要假设;先获取最新文档:主文档 https://docs.convex.dev/components、组件编写 https://docs.convex.dev/components/authoring、更广上下文 https://docs.convex.dev/llms.txt。
- 将 Convex 组件做成自包含包,包含与主应用隔离的数据库表、函数(queries、mutations、actions)、TypeScript 类型和 validators,以及可选前端 hooks。
- 使用组件目录结构:my-convex-component/ 下包含 package.json、tsconfig.json、README.md、src/,src/ 下有 index.ts(主导出)、component.ts(组件定义)、schema.ts(组件 schema)、functions/(queries.ts、mutations.ts、actions.ts),以及 convex.config.ts(组件配置)。
- 创建 convex.config.ts:从 convex/server 导入 defineComponent,并导出 defineComponent('myComponent')。
- 创建 src/schema.ts:从 convex/server 导入 defineSchema、defineTable,从 convex/values 导入 v;用 defineSchema 定义 items 表(name: v.string()、data: v.any()、createdAt: v.number(),并 index('by_name', ['name']))和 config 表(key: v.string()、value: v.any(),并 index('by_key', ['key']));这些表隔离在该组件内。
- 创建 src/component.ts:从 convex/server 导入 defineComponent、ComponentDefinition,导入 schema 以及 queries、mutations;调用 defineComponent('myComponent', { schema, functions: { ...queries, ...mutations } }) 并默认导出。
- 在 src/functions/queries.ts 定义 query:使用 query 包装并提供 args、returns、handler;list 接收 limit: v.optional(v.number()),返回含 _id、name、data、createdAt 的数组对象,handler 用 ctx.db.query('items').order('desc').take(args.limit ?? 10);get 接收 name: v.string(),返回对象或 null,handler 用 ctx.db.query('items').withIndex('by_name', q => q.eq('name', args.name)).unique()。
- 在 src/functions/mutations.ts 定义 mutation:create 接收 name、data,返回 v.id('items'),handler 用 ctx.db.insert('items', { name: args.name, data: args.data, createdAt: Date.now() });update 接收 id、data,返回 v.null(),handler 用 ctx.db.patch(args.id, { data: args.data }) 并返回 null;remove 接收 id,返回 v.null(),handler 用 ctx.db.delete(args.id) 并返回 null。
- 创建 src/index.ts 主导出:export { default as component } from './component';export * from './functions/queries';export * from './functions/mutations';并导出消费者需要的类型,例如 export type { Id } from './_generated/dataModel'。
- 在消费应用的 convex/convex.config.ts 中使用组件:从 convex/server 导入 defineApp,导入 myComponent;const app = defineApp();app.use(myComponent, { name: 'myComponent' });export default app。
- 在消费应用代码中通过应用 API 访问组件函数:从 convex/react 导入 useQuery、useMutation,从 ../convex/_generated/api 导入 api;用 useQuery(api.myComponent.list, { limit: 10 }) 查询,用 useMutation(api.myComponent.create) 创建。
- 在 convex/convex.config.ts 中按需配置组件:app.use(myComponent) 基本用法;app.use(myComponent, { name: 'customName' }) 自定义名称;app.use(myComponent, { name: 'instance1' }) 和 app.use(myComponent, { name: 'instance2' }) 创建多个实例。
- 创建 src/hooks.ts 提供组件 hooks:从 convex/react 导入 useQuery、useMutation,从 convex/server 导入 FunctionReference;导出 useMyComponent(api: { list: FunctionReference<'query'>; create: FunctionReference<'mutation'> }),内部用 useQuery(api.list, {})、useMutation(api.create),返回 { items, createItem, isLoading: items === undefined }。
- 发布组件时配置 package.json:name、version、description、main 为 dist/index.js、types 为 dist/index.d.ts、files 包含 dist 和 convex.config.ts、scripts 有 build: tsc 和 prepublishOnly: npm run build、peerDependencies 有 convex ^1.0.0、devDependencies 有 convex ^1.17.0 和 typescript ^5.0.0、keywords 包含 convex 和 component。
- 发布组件时配置 tsconfig.json:compilerOptions 设置 target ES2020、module ESNext、moduleResolution bundler、declaration true、outDir dist、strict true、esModuleInterop true、skipLibCheck true;include 为 src/**/*;exclude 为 node_modules、dist。
- Rate Limiter 示例:在 rate-limiter/src/schema.ts 定义 requests 表(key: v.string()、timestamp: v.number()),建立 index('by_key', ['key']) 和 index('by_key_and_time', ['key', 'timestamp'])。
- Rate Limiter 示例:在 rate-limiter/src/functions/mutations.ts 定义 checkLimit mutation,args 为 key、limit、windowMs,returns 为对象 { allowed: v.boolean(), remaining: v.number(), resetAt: v.number() }。
- Rate Limiter checkLimit handler:now = Date.now(),windowStart = now - windowMs;用 by_key_and_time 查询 key 等于 args.key 且 timestamp 小于 windowStart 的旧记录并逐条 ctx.db.delete;用 by_key 查询当前请求。
- Rate Limiter checkLimit handler 继续:remaining = Math.max(0, limit - currentRequests.length);allowed = remaining > 0;如果 allowed 则 ctx.db.insert('requests', { key: args.key, timestamp: now });oldestRequest = currentRequests[0];resetAt = oldestRequest ? oldestRequest.timestamp + windowMs : now + windowMs;返回 { allowed, remaining: remaining - (allowed ? 1 : 0), resetAt }。
- 在消费应用中使用 Rate Limiter:用 useMutation(api.rateLimiter.checkLimit) 得到 checkLimit;返回异步函数接收 action,调用 checkLimit({ key: 'user-action', limit: 10, windowMs: 60000 });如果 !result.allowed 抛出错误 Rate limited. Try again at ${new Date(result.resetAt)};否则 await action()。
- 最佳实践:不要运行 npx convex deploy,除非明确指示。
- 最佳实践:不要运行任何 git 命令,除非明确指示。
- 最佳实践:保持组件表隔离,不要引用主应用表。
- 最佳实践:为消费者导出清晰的 TypeScript 类型。
- 最佳实践:记录所有公共函数及其参数。
- 最佳实践:组件发布使用语义化版本。
- 最佳实践:包含带示例的完整 README。
- 最佳实践:发布前在隔离环境中测试组件。
- 常见陷阱:避免跨引用表;组件表应自包含。
- 常见陷阱:避免缺少类型导出;导出所有必要类型。
- 常见陷阱:避免硬编码配置;使用组件选项进行自定义。
- 常见陷阱:避免无版本管理;遵循语义化版本。
- 常见陷阱:避免文档差;记录所有公共 API。
- 参考 Convex 文档 https://docs.convex.dev/、Convex LLMs.txt https://docs.convex.dev/llms.txt、Components https://docs.convex.dev/components、Component Authoring https://docs.convex.dev/components/authoring。
适用边界 · 注意事项
- 未使用 Convex 或无法安装/依赖 Convex 平台时不适用。
- 仅在单个应用内部使用、无需跨项目复用同一组件时,不必抽取为 Convex 组件。
- 若无法遵守组件表隔离、类型导出、语义化版本和隔离测试等约束,不适合使用该流程。