Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: middleapi/orpc
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.14.1
Choose a base ref
...
head repository: middleapi/orpc
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.14.2
Choose a head ref
  • 3 commits
  • 94 files changed
  • 6 contributors

Commits on May 4, 2026

  1. Configuration menu
    Copy the full SHA
    ba3c437 View commit details
    Browse the repository at this point in the history

Commits on May 6, 2026

  1. fix: mark @orpc packages as sideEffect-free for cross-pkg tree-shaking (

    #1540)
    
    Closes #1490.
    
    ## Background
    
    Importing only `oz.file()` from `@orpc/zod` was pulling ~21 kB of
    `@orpc/server` runtime into client bundles via the chain:
    
    ```
    @orpc/zod  β†’  @orpc/openapi  β†’  @orpc/server
    ```
    
    Because `@orpc/zod` re-exports `JSONSchemaFormat` etc. from
    `@orpc/openapi`, and `@orpc/openapi/dist/index.mjs` has top-level
    `import { ORPCError, createRouterClient } from '@orpc/server'`. Those
    top-level cross-package imports are preserved by the consumer's bundler
    unless the package is annotated as side-effect free, because the bundler
    cannot otherwise prove the import has no observable effect.
    
    ## Fix
    
    Add `"sideEffects": false` to the all oRPC's packages
    
    I audited the source for global mutations / prototype patches /
    side-effecting class registrations at import time and found none β€” the
    published modules are pure, so the annotation is safe.
    
    ## Reproducer
    
    Stand-alone Vite app that mirrors the issue body:
    
    ```ts
    // client.ts
    import { oc } from '@orpc/contract'
    import { z } from 'zod/v3'
    import { oz } from '@orpc/zod'
    
    export const myRouter = oc.router({
      downloadFile: oc
        .route({ method: 'GET', path: '/download/{id}' })
        .input(z.object({ id: z.string() }))
        .output(oz.file()),
    })
    ```
    
    Bundled with `vite build --minify esbuild --target es2022` and
    `external: ['zod', 'zod/v3']`:
    
    | Variant | Bundle | Gzipped | `@orpc/server` symbols leaked |
    |---|---|---|---|
    | Before this PR | **37.9 kB** | 9.54 kB | `ORPCError`, `Procedure`,
    `createRouterClient`, `isProcedure`, `resolveContractProcedures` |
    | After this PR | **14.8 kB** | 4.76 kB | none from `@orpc/server` (the
    remaining `ORPCError` is from `@orpc/contract`, which is legitimately
    needed because `oc.router()` returns objects that use it) |
    
    **Net savings: 23.1 kB minified (61% reduction) / 4.78 kB gzipped
    (50%).**
    
    ## Why this rather than the subpath split suggested in #1490
    
    The reporter (correctly) suggested splitting `ZodToJsonSchemaConverter`
    into a separate `@orpc/zod/json-schema` subpath and removing it from the
    main entry. That would also fix the bug, but it is a **breaking change**
    for everyone currently importing the converter from `@orpc/zod` (incl.
    all in-repo playgrounds that use `@orpc/zod/zod4`'s sister export,
    README example, etc.) and the subpath split is bundler-independent only
    insofar as users don't accidentally re-export the heavy entry
    transitively.
    
    `sideEffects: false` is **non-breaking**, lands in 6 lines, and β€” as the
    numbers show β€” actually achieves the bundle reduction the reporter
    expected. If the cross-package tree-shaking turns out insufficient for
    some consumer's bundler, the subpath split is still available as a
    follow-up.
    
    The reporter's original claim that `sideEffects: false` alone wouldn't
    fix this assumed it was set on `@orpc/zod` only; the chain only
    tree-shakes when **every** package along the cross-package import path
    is marked, which is what this PR does.
    
    ## Local gates
    
    - `pnpm --filter='./packages/*' run -r build` βœ“ all packages build, dist
    outputs unchanged in shape (sideEffects flag does not alter the
    rolled-up bundle, only the `package.json` of the published artifact)
    - `pnpm test` βœ“ 4720 pass / 48 skipped / 5 todo across 280 test files
    (untouched by this change)
    - `pnpm run type:check` βœ“ clean across all packages
    - `pnpm lint` βœ“ clean (auto-formatter sorted the new key after
    `keywords` per `jsonc/sort-keys`)
    
    I was happy to find this fits in 6 lines β€” happy to fold in the subpath
    split as a follow-up if any reviewer measures their bundler still needs
    it.
    
    πŸ€– Generated with [Claude Code](https://claude.com/claude-code)
    
    <!-- This is an auto-generated comment: release notes by coderabbit.ai
    -->
    ## Summary by CodeRabbit
    
    * **Chores**
    * Updated package metadata across many packages to mark them as
    side-effect free for improved bundling behavior.
    * **New Features**
    * Exposed a package entry point for one package, updating its public
    exports.
    <!-- end of auto-generated comment: release notes by coderabbit.ai -->
    
    ---------
    
    Co-authored-by: voidborne-d <[email protected]>
    Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
    Co-authored-by: Dinh Le <[email protected]>
    4 people authored May 6, 2026
    Configuration menu
    Copy the full SHA
    683f2ee View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    af1a814 View commit details
    Browse the repository at this point in the history
Loading