Skip to content

ESM re-export from CJS generates incorrect property access in cross-chunk imports #25867

@robobun

Description

@robobun

Description

When an ESM file re-exports a named export from a CommonJS module and the re-exporting file is split into a separate chunk, the consumer generates incorrect code that accesses a property on an already-resolved value.

Reproduction

// cjs-module.js
module.exports = { value: "from-cjs" };

// esm-reexport.ts
export { value } from "./cjs-module.js";

// consumer.ts
import { value } from "./esm-reexport";
console.log(value);

Build with:

bun build --outdir=dist --splitting ./consumer.ts ./esm-reexport.ts

Expected Output

// consumer.js
import { value } from "./esm-reexport.js";
console.log(value);

Output: from-cjs

Actual Output

// consumer.js
import { value as import_cjs_module } from "./esm-reexport.js";
console.log(import_cjs_module.value);  // BUG: .value access on already-resolved value

Output: undefined

Analysis

The bug is in js_printer.zig around lines 2884-2916. When printing an EImportIdentifier with a namespace_alias, the fallback case always prints the alias as a property access (namespace_ref.alias), even when dealing with a cross-chunk import where the value is directly imported.

The esm-reexport.js correctly exports:

var export_value = import_cjs_module.value;
export { export_value as value };

But the consumer incorrectly treats value as if it still needs the .value property access.

Workaround

Use namespace import instead of named re-export:

// esm-reexport.ts
import * as cjs from "./cjs-module.js";
export const value = cjs.value;

Environment

  • Bun version: 1.2+
  • Occurs with --splitting when re-exporting file is in a separate chunk

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions