Skip to content

compile: prune modules reachable only through unused re-exports of side-effect-free packages (Bun's graph: 4,063 modules; perry compiles and initializes 7,897 for the same OpenCode entry) #10180

Description

@proggeramlug

Parent: #10106 (OpenCode startup) / #10107. Related: #9133 (full-source builds), #10173 (mid-size literal compile cliff), the per-function code-size campaign.

Observation

For the same entry (packages/opencode/src/index.ts, OpenCode v1.18.30, bun condition) Bun's bundler graph has 4,063 modules; perry compile --platform bun collects and compiles 7,897 (audit: 2,067 first-party, 5,830 from 422 packages). The native binary then runs every one of those module initializers before main parses argv, which is most of the 2.0 s user CPU of opencode --version (bun: 0.4 s), and every module is ~130 KB of .text on average in the 1.05 GB binary.

Where the extra modules come from (from perry-cache/audit.json vs Bun's metafile, both saved under secret-tests/opencode-1.18.30-inventory/):

  • Bun drops modules that are only reached through unused re-exports of side-effect-free packages ("sideEffects": false / pure barrels): remeda 24 modules in Bun vs 170 in perry, effect 225 vs 294, openai 145 vs 152, ai (227 in perry) similarly; barrel index.ts files that export * from "./x" pull in every sibling even when the importer names one symbol.
  • 31 packages are present in several versions; @ai-sdk/provider-utils in 11 versions = 1,012 modules, @ai-sdk/provider 6 versions = 648, zod 3 versions = 189, semver 3, @ai-sdk/openai 3, entities 3. Bun's graph has 3 provider-utils versions. Perry follows each provider package's nested copy; that is correct resolution, but most of those copies are reached only through barrels of providers that OpenCode loads lazily via import() (BUNDLED_PROVIDERS in src/provider/provider.ts:113).
  • node/bun condition twins are only 6 files, negligible.

Ask

Collection-time pruning that matches the bundler's semantics without changing program behaviour:

  1. For packages that declare "sideEffects": false (or whose modules have no top-level effects by analysis), do not compile or initialize modules that are reached only through export { x } from / export * from re-exports whose bindings the importer never uses (bundler-style live-binding tree shaking at the module level; the module stays available for dynamic import).
  2. Keep dynamic-import-only subgraphs out of the eager init order and out of the eager .text if possible (verify with the OpenCode graph that prettier/typescript/babel are not initialized on --version).
  3. Report the pruned count in the compile summary (Found N module(s): …, M pruned as unreferenced side-effect-free re-exports).

Acceptance

  • OpenCode v1.18.30 collects within ~10 % of Bun's 4,063 modules; opencode --version user CPU and binary .text reported before/after.
  • A fixture with a sideEffects: false barrel proves the unused sibling is neither compiled nor initialized, and that a sibling with a top-level side effect (or a package without the flag) is still initialized in ESM order.
  • Node-parity suites unchanged.

Activity

  1. added
    enhancementNew capability or improvement
    performanceRuntime, compile-time, build-size, or memory performance
    on Sep 13, 2026
  2. proggeramlug commented on Sep 14, 2026

    @proggeramlug
    ContributorAuthor

    PR: #10245

    Collection falls from 7,897 to 7,068 modules (829 / 10.5% removed); eager modules fall from 2,433 to 2,376. The 43 source-graph tests pass. This remains above the requested Bun-relative target.

    The one full compile completed all 7,068 modules but failed at linking Babel transformAsync from OpenTUI Solid. A minimal CommonJS getter-forwarding fixture reproduces the same missing symbol on pristine bb9aa5a, pruning disabled, and pruning enabled. No CLI ladder or after CPU/size result is available. The PR includes the safety rule, package counts, test evidence, exact commands, and the blocker reproducer; generated objects are retained in the lane cache. Refs #10107.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew capability or improvementperformanceRuntime, compile-time, build-size, or memory performance

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions