2626 * like `ink-frame.tsx` and third-party packages like `ink`,
2727 * `react`) so the file is fully self-contained.
2828 *
29- * Some of the inlined packages (e.g. `signal-exit`, used by Ink)
30- * are CJS modules that call `require("assert")` etc. esbuild
31- * wraps these in `__require` shims that throw "Dynamic require
32- * is not supported" at runtime. The banner injects a real
33- * `require` function via `createRequire` so CJS dependencies
34- * resolve Node builtins correctly inside the ESM bundle.
35- *
3629 * Non-TypeScript files (plain `.js`) are copied verbatim.
3730 *
3831 * Used by `script/build.ts` (single-file executable) and
4437
4538import { copyFileSync , mkdirSync , readFileSync } from "node:fs" ;
4639import { basename , dirname , extname , resolve as resolvePath } from "node:path" ;
47- import { build as esbuildBuild , type Plugin } from "esbuild" ;
40+ import type { Plugin } from "esbuild" ;
4841
4942const TEXT_IMPORT_NS = "text-import" ;
5043const ANY_FILTER = / .* / ;
@@ -53,36 +46,36 @@ const ANY_FILTER = /.*/;
5346const TS_EXTENSIONS = new Set ( [ ".ts" , ".tsx" , ".jsx" ] ) ;
5447
5548/**
56- * Banner injected into the pre-bundled sidecar JS. Provides a real
57- * `require` function so esbuild's CJS-wrapping `__require` shims
58- * can resolve Node.js builtins (`assert`, `events`, etc.) at runtime.
59- * Without this, `signal-exit` and other CJS deps of Ink throw
60- * "Dynamic require of 'assert' is not supported".
61- */
62- const REQUIRE_BANNER =
63- 'import { createRequire as ___cr } from "node:module";' +
64- " var require = ___cr(import.meta.url);" ;
65-
66- /**
67- * Pre-bundle a TypeScript/TSX source file into self-contained JS.
68- * All dependencies (local modules AND npm packages) are inlined;
69- * only `node:*` builtins are external since Bun resolves them
70- * natively inside `/$bunfs/`.
49+ * Pre-bundle a TypeScript/TSX source file into a self-contained JS module
50+ * using Bun.build. All dependencies (local modules AND npm packages) are
51+ * inlined; Bun handles node:* builtins natively so no explicit externals
52+ * are needed.
53+ *
54+ * Using Bun.build (rather than esbuild) is critical. esbuild wraps CJS
55+ * packages (e.g. `signal-exit`, `parse-keypress`) in `__commonJS` helpers.
56+ * When Bun.compile later embeds the esbuild output as a `with { type: "file"
57+ * }` asset, it injects `__promiseAll` helpers at wrong positions inside those
58+ * wrappers, producing `SyntaxError: Unexpected identifier '__promiseAll'` at
59+ * runtime. Bun.build produces output that Bun.compile recognises natively and
60+ * handles without mis-injecting the helper.
7161 */
7262async function prebundleTs ( sourcePath : string , outPath : string ) : Promise < void > {
73- await esbuildBuild ( {
74- entryPoints : [ sourcePath ] ,
75- bundle : true ,
76- outfile : outPath ,
77- platform : "node" ,
78- target : "esnext" ,
79- format : "esm" ,
80- jsx : "automatic" ,
81- external : [ "node:*" ] ,
82- banner : { js : REQUIRE_BANNER } ,
63+ const outdir = dirname ( outPath ) ;
64+ const result = await Bun . build ( {
65+ entrypoints : [ sourcePath ] ,
66+ target : "bun" ,
67+ outdir,
68+ naming : "[name].js" ,
69+ define : {
70+ "process.env.NODE_ENV" : JSON . stringify ( "production" ) ,
71+ } ,
8372 minify : false ,
84- write : true ,
8573 } ) ;
74+ if ( ! result . success ) {
75+ throw new Error (
76+ result . logs . map ( ( l ) => String ( l ) ) . join ( "\n" ) || "unknown error"
77+ ) ;
78+ }
8679}
8780
8881/** Resolve the output directory from the parent esbuild config. */
0 commit comments