Skip to content

Barrel-style entrypoints silently produce broken .d.ts (re-exports point at sibling files that arent emitted) #3976

Description

@glennmichael123

Discovered while debugging @stacksjs/bun-router@0.0.5's published types being effectively empty. Filing because the failure mode is silent and the recovery path isn't obvious.

Repro

build.ts:

import { dts } from 'bun-plugin-dtsx'

await Bun.build({
  entrypoints: ['src/index.ts', 'src/cli.ts'],
  outdir: './dist',
  splitting: true,
  target: 'bun',
  format: 'esm',
  plugins: [dts({ entrypoints: ['index.ts', 'cli.ts'] })],
})

src/index.ts (a typical barrel):

export * from './router'
export * from './middleware'
export * from './types'
export * from './utils'
// …

Run the build. Result in dist/:

dist/
  index.d.ts   ← contains: export * from './router'; export * from './types'; …
  cli.d.ts
  index.js
  cli.js
  chunk-*.js

No dist/router.d.ts, no dist/types.d.ts, no dist/router/, no dist/types/. The barrel re-exports point at sibling modules that were never emitted, because they weren't in the plugin's entrypoints array.

Effect

TypeScript silently treats every export * from './missing' as exporting nothing. Consumers see:

TS2305: Module '"@stacksjs/bun-router"' has no exported member 'EnhancedRequest'
TS2305: Module '"@stacksjs/bun-router"' has no exported member 'Router'
TS2305: Module '"@stacksjs/bun-router"' has no exported member 'ActionHandler'
…

Cascading further: types that do resolve get inferred as any (because their dependent types are missing), causing TS7034 (Variable 'route' implicitly has type 'any' in some locations…) at usage sites. The runtime JS is fine — everything's bundled into index.js. Just the types are broken.

This already shipped to npm: @stacksjs/bun-router@0.0.5. A fresh app installing it gets a router with no types.

bundle: true doesn't fix it

plugins: [dts({ entrypoints: ['index.ts', 'cli.ts'], bundle: true })]

Output is still:

// dist/index.d.ts
export * from './router'
export * from './types'
// …

bundle: true concatenates the entrypoint files into one output, but doesn't follow export * from './x' and inline what those files export. Other dts bundlers (rollup-plugin-dts, tsup, microsoft/api-extractor) follow re-exports and inline reachable types — that's what "bundle" usually means in this space.

Workarounds we tried

  1. Pass every source file as an entrypoint: dts({ entrypoints: glob('src/**/*.ts') }). Works (mirrors src tree to dist), but slow with many files (~7 minutes for 131 files in our repro before we cancelled it).

  2. Replace the dts plugin with tsc -p tsconfig.build.json: ran in parallel with Bun.build(). Fast, complete output, but defeats the purpose of using bun-plugin-dtsx.

We ended up with #2.

What I'd expect

At least one of:

  • bundle: true actually bundles — follows export * / export {x} from './path' chains, inlines reachable declarations into a single rolled-up index.d.ts. This is the most useful default and matches how every other dts bundler behaves.
  • Auto-include reachable subpaths — when an entrypoint's .d.ts re-exports from sibling modules, emit .d.ts for those siblings too. Recursively.
  • Fail loudly — at minimum, emit a build warning/error when the generated .d.ts references a sibling that isn't being emitted: "Generated dist/index.d.ts re-exports from ./router, but no entrypoint produces dist/router.d.ts. The output is unusable." This alone would have saved us hours.

Environment

  • bun-plugin-dtsx@0.9.13
  • @stacksjs/dtsx@0.9.13
  • Bun 1.3.10
  • macOS 14.x

Cross-reference

Real-world impact: published @stacksjs/bun-router@0.0.5 shipped with broken types. Companion bun-router proposal/cleanup will follow once this is sorted (or worked around).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions