convex-js icon indicating copy to clipboard operation
convex-js copied to clipboard

optimize ApiFromModules type performance

Open ssalbdivad opened this issue 3 months ago • 0 comments

This pull request optimizes ApiFromModules and adds type-level benchmarks using @ark/attest so that they can be tested and added to CI if desired.

A large portion of the diff will consist of fake_chef files copied from a generated Convex project as a realistic benchmark and can generally be ignored. All meaningful optimizations occurred in src/server/api.ts.

The biggest improvements come from avoiding the creation of intermediate object types, additional intersections, and adding a fast path for modules with no segmented (i.e. A/B) paths.

This lead to a ~27% improvement in type performance on the fast path and ~14% for segmented modules. Similar strategies could be applied to other types in the repo for further improvements, but generally I found the types I reviewed to be relatively efficient and well-written, so props to the team 👏

As mentioned to @thomasballinger, another promising avenue for followup type optimization would be deduplicating object literals defined in _generated/api.d.ts. Here's an example of how that could be achieved:

// current
export declare const components: {
    rateLimiter: {
        lib: {
            checkRateLimit: FunctionReference<
                "query",
                "internal",
                {
                    config:
                        | {
                              capacity?: number
                              kind: "token bucket"
                              maxReserved?: number
                              period: number
                              rate: number
                              shards?: number
                          }
                        | {
                              capacity?: number
                              kind: "fixed window"
                              maxReserved?: number
                              period: number
                              rate: number
                              shards?: number
                              start?: number
                          }
                    count?: number
                    key?: string
                    name: string
                    reserve?: boolean
                    throws?: boolean
                },
                | { ok: true; retryAfter?: number }
                | { ok: false; retryAfter: number }
            >
        }
    }
}

// example optimization (should be reused for other components as well)
interface BaseConfig {
    capacity?: number
    maxReserved?: number
    period: number
    rate: number
    shards?: number
}

interface FixedWindowConfig extends BaseConfig {
    kind: "fixed window"
    start?: number
}

interface TokenBucketConfig extends BaseConfig {
    kind: "token bucket"
}

interface CommonArgs {
    config: FixedWindowConfig | TokenBucketConfig
    count?: number
    key?: string
    name: string
    reserve?: boolean
    throws?: boolean
}

type ReturnType =
    | { ok: true; retryAfter?: number }
    | { ok: false; retryAfter: number }

export declare const components: {
    rateLimiter: {
        lib: {
            checkRateLimit: FunctionReference<
                "query",
                "internal",
                CommonArgs,
                ReturnType
            >
        }
    }
}

Applying a similar approach to a large number of object literals in Prisma's generated types led to a ~50% performance improvement, so this could be very impactful for large projects with many such components.


By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

ssalbdivad avatar Aug 21 '25 20:08 ssalbdivad