fix(tui): drop ink-text-input re-export from @hermes/ink entry-exports (#31227)

The dashboard TUI bundle hung at startup with only 141 bytes of ANSI
reset sequences and a blank screen forever. Root cause: esbuild's
lightweight `__esm` helper at the top of `dist/entry.js` does not
await nested async init, so a circular async cycle in the module
graph never resolves. The cycle came from re-exporting
``TextInput`/`UncontrolledTextInput`` from `'ink-text-input'` here —
that npm package depends on the upstream `ink` package, whose graph
loops back through React + our in-tree `@hermes/ink` ink fork. The
result: `init_entry_exports` was emitted as `async … await
init_build4()` (where `build4` is `node_modules/ink-text-input/build`),
and the top-level `await Promise.all([init_entry_exports().then(...)])`
in `src/entry.tsx` deadlocked waiting on the dangling Promise.

Nobody in `ui-tui/` actually imports `TextInput` from `@hermes/ink` —
the composer uses the in-tree `src/components/textInput.tsx` widget
instead. Drop the re-export from the source so the bundle no longer
inlines the upstream ink graph at all. Callers that legitimately want
the upstream widget can still import it from the dedicated
`@hermes/ink/text-input` subpath, which sits outside `entry-exports`
and so does not get inlined into consumers' bundles.

After the fix:
* `dist/entry.js` shrinks from 2.9MB → 2.4MB (~11.5k fewer bundled
  lines) with zero `async __esm` wrappers remaining.
* `init_entry_exports` is now a synchronous `__esm` module.
* The bundle's top-level await chain resolves in ~30ms instead of
  hanging.
This commit is contained in:
xxxigm 2026-05-24 08:45:22 +07:00 committed by Teknium
parent a658f3b28b
commit 18297899d7
2 changed files with 21 additions and 3 deletions

View file

@ -36,5 +36,6 @@ export type { Instance, RenderOptions, Root } from './src/ink/root.ts'
export { stringWidth } from './src/ink/stringWidth.ts'
export type { MouseTrackingMode } from './src/ink/termio/dec.ts'
export { wrapAnsi } from './src/ink/wrapAnsi.ts'
export { default as TextInput, UncontrolledTextInput } from 'ink-text-input'
export type { Props as TextInputProps } from 'ink-text-input'
// 'ink-text-input' types deliberately not re-exported here; see
// src/entry-exports.ts for the full rationale (#31227). Use the
// '@hermes/ink/text-input' subpath when the upstream widget is needed.

View file

@ -29,4 +29,21 @@ export { stringWidth } from './ink/stringWidth.js'
export { isXtermJs } from './ink/terminal.js'
export type { MouseTrackingMode } from './ink/termio/dec.js'
export { wrapAnsi } from './ink/wrapAnsi.js'
export { default as TextInput, UncontrolledTextInput } from 'ink-text-input'
// NOTE: Do not re-export from 'ink-text-input' here.
//
// 'ink-text-input' depends on the npm 'ink' package; pulling it in from
// this re-export drags an entire second copy of ink (and its async
// top-level init chain) into any caller that bundles `@hermes/ink` from
// source. esbuild's `__esm` helper then deadlocks on the circular
// async init between the two ink graphs — the dashboard TUI bundle
// stalls at startup with only 141 bytes of ANSI reset output, blank
// screen forever (#31227).
//
// Consumers that actually want the upstream ink-text-input widget must
// import it via the dedicated subpath:
//
// import TextInput from '@hermes/ink/text-input'
//
// which still resolves through this package's `./text-input` export,
// just outside the entry-exports surface that gets inlined by callers.