diff --git a/src/ast/nodes.rs b/src/ast/nodes.rs index 339fb820ea40..3231a72762c4 100644 --- a/src/ast/nodes.rs +++ b/src/ast/nodes.rs @@ -1089,6 +1089,7 @@ pub type PartList<'a> = bun_alloc::ArenaVec<'a, Part>; #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum PartTag { None, + JsxImport, Runtime, ReactCompiler, DirnameFilename, diff --git a/test/bundler/bundler_jsx.test.ts b/test/bundler/bundler_jsx.test.ts index 259fc2de5b9b..bd200ef9c693 100644 --- a/test/bundler/bundler_jsx.test.ts +++ b/test/bundler/bundler_jsx.test.ts @@ -1146,6 +1146,26 @@ describe("bundler", () => { }, }); + // Transpile-only output (--no-bundle, same single-file path as the + // runtime transpiler) never tree-shakes parts, so the synthesized runtime + // import must survive even when every JSX expression is dead. + itBundled("jsx/AutoImportKeptWhenNotBundling", { + files: { + "/index.tsx": /* tsx */ ` + const unused =
dead
; + console.log('only-this'); + `, + }, + bundling: false, + jsx: { runtime: "automatic" }, + onAfterBundle(api) { + const file = api.readFile("out.js"); + expect(file).toMatch(/from\s*"react\/jsx-(dev-)?runtime"/); + // Transpile-only keeps the hashed import alias, e.g. `jsx_w77yafs4(`. + expect(file).toMatch(/jsx(DEV)?(_\w+)?\(/); + }, + }); + // Two entry modules: one where JSX survives, one where it is all dead. // The JSX source must be bundled (for the live entry) without leaking an // extra import into the dead entry's chunk.