mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
## Summary
- Fixes incorrect banner positioning when using `--banner` with
`--format=cjs` and `--target=bun`
- Ensures Bun-specific comments (`// @bun @bun-cjs`) appear before user
banner content
- Properly extracts and positions hashbangs from banner content
## Problem
When using `--banner` with `--format=cjs --target=bun`, the banner was
incorrectly placed before the `// @bun @bun-cjs` comment and CJS wrapper
function, breaking the module format that Bun expects.
## Solution
Implemented proper ordering:
1. **Hashbang** (from source file or extracted from banner if it starts
with `#!`)
2. **@bun comments** (e.g., `// @bun`, `// @bun @bun-cjs`, `// @bun
@bytecode`)
3. **CJS wrapper** `(function(exports, require, module, __filename,
__dirname) {`
4. **Banner content** (excluding any extracted hashbang)
## Test plan
- [x] Added comprehensive tests for banner positioning with CJS/ESM and
Bun target
- [x] Tests cover hashbang extraction from banners
- [x] Tests verify proper ordering with bytecode generation
- [x] All existing tests pass
🤖 Generated with [Claude Code](https://claude.ai/code)
---------
Co-authored-by: Claude <noreply@anthropic.com>
306 lines
7.2 KiB
TypeScript
306 lines
7.2 KiB
TypeScript
import { describe } from "bun:test";
|
|
import { ESBUILD, itBundled } from "./expectBundled";
|
|
|
|
describe("bundler", () => {
|
|
itBundled("naming/EntryNamingCollission", {
|
|
files: {
|
|
"/a/entry.js": /* js */ `
|
|
console.log(1);
|
|
`,
|
|
"/b/entry.js": /* js */ `
|
|
console.log(2);
|
|
`,
|
|
},
|
|
entryNaming: "[name].[ext]",
|
|
entryPointsRaw: ["./a/entry.js", "./b/entry.js"],
|
|
bundleErrors: {
|
|
// expectBundled does not support newlines.
|
|
"<bun>": [`Multiple files share the same output path`],
|
|
},
|
|
});
|
|
itBundled("naming/ImplicitOutbase1", {
|
|
files: {
|
|
"/a/entry.js": /* js */ `
|
|
console.log(1);
|
|
`,
|
|
"/b/entry.js": /* js */ `
|
|
console.log(2);
|
|
`,
|
|
},
|
|
entryPointsRaw: ["./a/entry.js", "./b/entry.js"],
|
|
run: [
|
|
{
|
|
file: "/out/a/entry.js",
|
|
stdout: "1",
|
|
},
|
|
{
|
|
file: "/out/b/entry.js",
|
|
stdout: "2",
|
|
},
|
|
],
|
|
});
|
|
itBundled("naming/ImplicitOutbase2", {
|
|
files: {
|
|
"/a/hello/entry.js": /* js */ `
|
|
import data from '../dependency'
|
|
console.log(data);
|
|
`,
|
|
"/a/dependency.js": /* js */ `
|
|
export default 1;
|
|
`,
|
|
"/a/hello/world/entry.js": /* js */ `
|
|
console.log(2);
|
|
`,
|
|
"/a/hello/world/a/a/a/a/a/a/a/entry.js": /* js */ `
|
|
console.log(3);
|
|
`,
|
|
},
|
|
entryPointsRaw: ["./a/hello/entry.js", "./a/hello/world/entry.js", "./a/hello/world/a/a/a/a/a/a/a/entry.js"],
|
|
run: [
|
|
{
|
|
file: "/out/entry.js",
|
|
stdout: "1",
|
|
},
|
|
{
|
|
file: "/out/world/entry.js",
|
|
stdout: "2",
|
|
},
|
|
{
|
|
file: "/out/world/a/a/a/a/a/a/a/entry.js",
|
|
stdout: "3",
|
|
},
|
|
],
|
|
});
|
|
itBundled("naming/EntryNamingTemplate1", {
|
|
files: {
|
|
"/a/hello/entry.js": /* js */ `
|
|
import data from '../dependency'
|
|
console.log(data);
|
|
`,
|
|
"/a/dependency.js": /* js */ `
|
|
export default 1;
|
|
`,
|
|
"/a/hello/world/entry.js": /* js */ `
|
|
console.log(2);
|
|
`,
|
|
"/a/hello/world/a/a/a/a/a/a/a/entry.js": /* js */ `
|
|
console.log(3);
|
|
`,
|
|
},
|
|
entryNaming: "files/[dir]/file.[ext]",
|
|
entryPointsRaw: ["./a/hello/entry.js", "./a/hello/world/entry.js", "./a/hello/world/a/a/a/a/a/a/a/entry.js"],
|
|
run: [
|
|
{
|
|
file: "/out/files/file.js",
|
|
stdout: "1",
|
|
},
|
|
{
|
|
file: "/out/files/world/file.js",
|
|
stdout: "2",
|
|
},
|
|
{
|
|
file: "/out/files/world/a/a/a/a/a/a/a/file.js",
|
|
stdout: "3",
|
|
},
|
|
],
|
|
});
|
|
itBundled("naming/EntryNamingTemplate2", {
|
|
todo: true,
|
|
files: {
|
|
"/src/first.js": /* js */ `
|
|
console.log(1);
|
|
`,
|
|
"/src/second/third.js": /* js */ `
|
|
console.log(2);
|
|
`,
|
|
},
|
|
entryNaming: "[ext]/prefix[dir]suffix/file.[ext]",
|
|
entryPointsRaw: ["./src/first.js", "./src/second/third.js"],
|
|
run: [
|
|
{
|
|
file: "/out/js/prefix/secondsuffix/file.js",
|
|
stdout: "2",
|
|
},
|
|
{
|
|
file: "/out/js/prefix/suffix/file.js",
|
|
stdout: "1",
|
|
},
|
|
],
|
|
});
|
|
itBundled("naming/AssetNaming", {
|
|
files: {
|
|
"/src/lib/first/file.js": /* js */ `
|
|
import file from "../second/data.file";
|
|
console.log(file);
|
|
`,
|
|
"/src/lib/second/data.file": `
|
|
this is a file
|
|
`,
|
|
},
|
|
root: "/src",
|
|
entryNaming: "hello.[ext]",
|
|
assetNaming: "test.[ext]",
|
|
entryPointsRaw: ["./src/lib/first/file.js"],
|
|
run: {
|
|
file: "/out/hello.js",
|
|
stdout: "./test.file",
|
|
},
|
|
});
|
|
itBundled("naming/AssetNamingMkdir", {
|
|
files: {
|
|
"/src/lib/first/file.js": /* js */ `
|
|
import file from "../second/data.file";
|
|
console.log(file);
|
|
`,
|
|
"/src/lib/second/data.file": `
|
|
this is a file
|
|
`,
|
|
},
|
|
root: "/src",
|
|
entryNaming: "hello.[ext]",
|
|
assetNaming: "subdir/test.[ext]",
|
|
entryPointsRaw: ["./src/lib/first/file.js"],
|
|
run: {
|
|
file: "/out/hello.js",
|
|
stdout: "./subdir/test.file",
|
|
},
|
|
});
|
|
itBundled("naming/AssetNamingDir", {
|
|
files: {
|
|
"/src/lib/first/file.js": /* js */ `
|
|
import file from "../second/data.file";
|
|
console.log(file);
|
|
`,
|
|
"/src/lib/second/data.file": `
|
|
this is a file
|
|
`,
|
|
},
|
|
root: "/src",
|
|
entryNaming: "hello.[ext]",
|
|
assetNaming: "[dir]/test.[ext]",
|
|
entryPointsRaw: ["./src/lib/first/file.js"],
|
|
loader: ESBUILD
|
|
? {
|
|
".file": "file",
|
|
}
|
|
: undefined,
|
|
run: [
|
|
{
|
|
file: "/out/hello.js",
|
|
stdout: "./lib/second/test.file",
|
|
},
|
|
],
|
|
});
|
|
itBundled("naming/AssetNoOverwrite", {
|
|
todo: true,
|
|
files: {
|
|
"/src/entry.js": /* js */ `
|
|
import asset1 from "./asset1.file";
|
|
import asset2 from "./asset2.file";
|
|
console.log(asset1, asset2);
|
|
`,
|
|
"/src/asset1.file": `
|
|
file 1
|
|
`,
|
|
"/src/asset2.file": `
|
|
file 2
|
|
`,
|
|
},
|
|
root: "/src",
|
|
assetNaming: "same-filename.txt",
|
|
entryPointsRaw: ["./src/entry.js"],
|
|
loader: {
|
|
".file": "file",
|
|
},
|
|
bundleErrors: {
|
|
"<bun>": ['Multiple files share the same output path: "same-filename.txt"'],
|
|
},
|
|
});
|
|
itBundled("naming/AssetFileLoaderPath1", {
|
|
files: {
|
|
"/src/entry.js": /* js */ `
|
|
import asset1 from "./asset1.file";
|
|
console.log(asset1);
|
|
`,
|
|
"/src/asset1.file": `
|
|
file 1
|
|
`,
|
|
//
|
|
"/out/hello/_": "",
|
|
},
|
|
root: "/src",
|
|
entryNaming: "lib/entry.js",
|
|
assetNaming: "hello/same-filename.txt",
|
|
entryPointsRaw: ["./src/entry.js"],
|
|
loader: {
|
|
".file": "file",
|
|
},
|
|
});
|
|
itBundled("naming/NonexistantRoot", ({ root }) => ({
|
|
backend: "cli",
|
|
files: {
|
|
"/src/entry.js": /* js */ `
|
|
import asset1 from "./asset1.file";
|
|
console.log(asset1);
|
|
`,
|
|
"/src/asset1.file": `
|
|
file 1
|
|
`,
|
|
},
|
|
root: "/lib",
|
|
entryPointsRaw: ["./src/entry.js"],
|
|
bundleErrors: {
|
|
// "<bun>": [`FileNotFound: failed to open root directory: ${root}/lib`],
|
|
},
|
|
}));
|
|
itBundled("naming/EntrypointOutsideOfRoot", {
|
|
todo: true,
|
|
files: {
|
|
"/src/hello/entry.js": /* js */ `
|
|
console.log(1);
|
|
`,
|
|
"/src/root/file.js": /* js */ `
|
|
console.log(2);
|
|
`,
|
|
},
|
|
root: "/src/root",
|
|
entryPointsRaw: ["./src/hello/entry.js"],
|
|
run: {
|
|
file: "/out/_.._/hello/file.js",
|
|
},
|
|
});
|
|
itBundled("naming/WithPathTraversal", {
|
|
files: {
|
|
"/a/hello/entry.js": /* js */ `
|
|
import data from '../dependency'
|
|
console.log(data);
|
|
`,
|
|
"/a/dependency.js": /* js */ `
|
|
export default 1;
|
|
`,
|
|
"/a/hello/world/entry.js": /* js */ `
|
|
console.log(2);
|
|
`,
|
|
"/a/hello/world/a/a/a/a/a/a/a/entry.js": /* js */ `
|
|
console.log(3);
|
|
`,
|
|
},
|
|
entryNaming: "foo/../bar/[dir]/file.[ext]",
|
|
entryPointsRaw: ["./a/hello/entry.js", "./a/hello/world/entry.js", "./a/hello/world/a/a/a/a/a/a/a/entry.js"],
|
|
run: [
|
|
{
|
|
file: "/out/bar/file.js",
|
|
stdout: "1",
|
|
},
|
|
{
|
|
file: "/out/bar/world/file.js",
|
|
stdout: "2",
|
|
},
|
|
{
|
|
file: "/out/bar/world/a/a/a/a/a/a/a/file.js",
|
|
stdout: "3",
|
|
},
|
|
],
|
|
});
|
|
});
|