Skip to content

feat: namespace → flat export migration (Bus proof-of-concept)#22685

Merged
kitlangton merged 1 commit into
devfrom
kit/namespace-treeshake
Apr 16, 2026
Merged

feat: namespace → flat export migration (Bus proof-of-concept)#22685
kitlangton merged 1 commit into
devfrom
kit/namespace-treeshake

Conversation

@kitlangton
Copy link
Copy Markdown
Contributor

Summary

  • Convert export namespace Bus { ... } to flat named exports in bus.ts with an export * as Bus barrel in index.ts — proving the tree-shake migration pattern works
  • Add script/unwrap-namespace.ts automation script (uses ast-grep for accurate namespace boundary detection)
  • Add specs/effect/namespace-treeshake.md migration plan and playbook

Why

TypeScript export namespace compiles to an IIFE that bundlers cannot tree-shake. The worst case: cli/error.ts imports { Provider } just for 6 .isInstance() checks, which forces inclusion of 20+ AI SDK packages. This inflates binary size, startup time, and memory.

export * as Bus from "./bus" gives bundlers a static export list they can analyze — same consumer API (Bus.publish, Bus.Service, etc.), but unused exports and their transitive deps get dropped.

What changed

Bus module (proof-of-concept):

  • src/bus/index.ts: 194 lines → 1 line (export * as Bus from "./bus")
  • src/bus/bus.ts: new file with the unwrapped flat exports
  • Zero import rewrites needed (was already index.ts)
  • All 18 bus tests pass, full typecheck clean

Automation:

  • script/unwrap-namespace.ts: one-command conversion per module with --dry-run support
  • specs/effect/namespace-treeshake.md: full migration plan, tutorial, and playbook

How to convert the next module

bun script/unwrap-namespace.ts src/auth/index.ts --dry-run  # preview
bun script/unwrap-namespace.ts src/auth/index.ts             # apply
# script prints import rewrite commands if needed
bun typecheck

Convert `export namespace Bus { ... }` to flat named exports in bus.ts
with an `export * as Bus` barrel in index.ts. This lets bundlers
tree-shake individual Bus exports instead of keeping the entire
namespace as an opaque IIFE.

Also adds the unwrap-namespace automation script and migration spec.
@kitlangton kitlangton enabled auto-merge (squash) April 16, 2026 01:16
@kitlangton kitlangton merged commit 02f2cf4 into dev Apr 16, 2026
13 checks passed
@kitlangton kitlangton deleted the kit/namespace-treeshake branch April 16, 2026 01:18
@jan-wilhelm
Copy link
Copy Markdown

Just fyi because I came across this PR - I was just looking into tree-shaking namespace exports, and it seems like the Bun bundler does not support tree-shaking export * as X from "./x" barrel exports, see issue here.

Curious if you have any workarounds to this or if you're expecting opencode to switch to a different bundler, but for now this seems to be a limitation of Bun

@kitlangton
Copy link
Copy Markdown
Contributor Author

@jan-wilhelm Good catch — we verified this and you're right. Neither Bun's bundler nor esbuild can tree-shake export * as X from "./mod" barrels (evanw/esbuild#1420, still open since 2021).

We tested all three bundlers with a minimal repro:

Pattern Bun esbuild Rollup
import { small } from "./mod" ✅ tree-shakes ✅ tree-shakes ✅ tree-shakes
import * as Mod from "./mod" ✅ tree-shakes ✅ tree-shakes ✅ tree-shakes
export * as Mod barrel ❌ keeps all ❌ keeps all ✅ tree-shakes

Only Rollup handles it — it does AST-level property access tracking through namespace re-exports.

The workaround: a Rollup tree-shaking pre-pass before Bun's compile step. Rollup resolves internal source and drops unused exports + their transitive deps, then Bun compiles the tree-shaken output into the binary. Draft PR: #22819


Generated by Claude Code

jerome-benoit pushed a commit to jerome-benoit/opencode that referenced this pull request Apr 16, 2026
xywsxp pushed a commit to xywsxp/opencode that referenced this pull request Apr 24, 2026
dgokeeffe pushed a commit to dgokeeffe/opencode-databricks that referenced this pull request May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants