mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
Fix duplicate exports when two entrypoints share symbols (#26089)
### What does this PR do? Fixes #5344 Fixes #6356 ### How did you verify your code works? Some test coverage --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Claude Bot <claude-bot@bun.sh>
This commit is contained in:
@@ -279,7 +279,6 @@ describe("bundler", () => {
|
||||
},
|
||||
});
|
||||
itBundled("splitting/ReExportESBuildIssue273", {
|
||||
todo: true,
|
||||
files: {
|
||||
"/a.js": `export const a = { value: 1 }`,
|
||||
"/b.js": `export { a } from './a'`,
|
||||
@@ -609,4 +608,28 @@ describe("bundler", () => {
|
||||
stdout: "42 true 42",
|
||||
},
|
||||
});
|
||||
// Test that CJS modules with dynamic imports to other CJS entry points work correctly
|
||||
// when code splitting causes the dynamically imported module to be in a separate chunk.
|
||||
// The dynamic import should properly unwrap the default export using __toESM.
|
||||
// Regression test for: dynamic import of CJS chunk returns { default: { __esModule, ... } }
|
||||
// and needs .then((m)=>__toESM(m.default)) to unwrap correctly.
|
||||
// Note: __esModule is required because bun optimizes simple CJS to ESM otherwise.
|
||||
itBundled("splitting/CJSDynamicImportOfCJSChunk", {
|
||||
files: {
|
||||
"/main.js": /* js */ `
|
||||
import("./impl.js").then(mod => console.log(mod.foo()));
|
||||
`,
|
||||
"/impl.js": /* js */ `
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.foo = () => "success";
|
||||
`,
|
||||
},
|
||||
entryPoints: ["/main.js", "/impl.js"],
|
||||
splitting: true,
|
||||
outdir: "/out",
|
||||
run: {
|
||||
file: "/out/main.js",
|
||||
stdout: "success",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
53
test/regression/issue/5344.test.ts
Normal file
53
test/regression/issue/5344.test.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { bunEnv, bunExe, tempDir } from "harness";
|
||||
|
||||
// https://github.com/oven-sh/bun/issues/5344
|
||||
// When one entry point re-exports from another entry point with code splitting,
|
||||
// the bundler was producing duplicate export statements.
|
||||
test("code splitting with re-exports between entry points should not produce duplicate exports", async () => {
|
||||
using dir = tempDir("issue-5344", {
|
||||
"entry-a.ts": `export { b } from "./entry-b.ts"; export function a() {}`,
|
||||
"entry-b.ts": `export function b() {}`,
|
||||
});
|
||||
|
||||
const result = await Bun.build({
|
||||
entrypoints: [`${dir}/entry-a.ts`, `${dir}/entry-b.ts`],
|
||||
outdir: `${dir}/dist`,
|
||||
splitting: true,
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.outputs.length).toBe(3); // entry-a.js, entry-b.js, chunk-*.js
|
||||
|
||||
const entryB = result.outputs.find(o => o.path.endsWith("entry-b.js"));
|
||||
expect(entryB).toBeDefined();
|
||||
|
||||
const entryBContent = await entryB!.text();
|
||||
|
||||
const exportMatches = entryBContent.match(/^export\s*\{/gm);
|
||||
expect(exportMatches?.length).toBe(1);
|
||||
|
||||
const entryAUrl = Bun.pathToFileURL(`${dir}/dist/entry-a.js`);
|
||||
const entryBUrl = Bun.pathToFileURL(`${dir}/dist/entry-b.js`);
|
||||
await using proc = Bun.spawn({
|
||||
cmd: [
|
||||
bunExe(),
|
||||
"-e",
|
||||
`
|
||||
import { a, b } from "${entryAUrl}";
|
||||
import { b as b2 } from "${entryBUrl}";
|
||||
console.log(typeof a, typeof b, b === b2);
|
||||
`,
|
||||
],
|
||||
env: bunEnv,
|
||||
cwd: String(dir),
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
||||
|
||||
expect(stderr).toBe("");
|
||||
expect(stdout.trim()).toBe("function function true");
|
||||
expect(exitCode).toBe(0);
|
||||
});
|
||||
Reference in New Issue
Block a user