-
Notifications
You must be signed in to change notification settings - Fork 5k
bundler: give the bundle thread a 16 MiB stack #38862
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,6 +43,24 @@ | |
| expect(await build.outputs[0].text()).toEqualIgnoringWhitespace(".hello{color:#00f}.hi{color:red}\n"); | ||
| }); | ||
|
|
||
| test("css @import chain of 1000 files does not overflow the bundle thread stack", async () => { | ||
| const files: Record<string, string> = {}; | ||
| const n = 1000; | ||
| for (let i = 0; i < n; i++) { | ||
| files[`c${i}.css`] = (i + 1 < n ? `@import "./c${i + 1}.css";\n` : "") + `.a${i} { color: red; }\n`; | ||
| } | ||
| const dir = tempDirWithFiles("bun-build-api-css-chain", files); | ||
|
|
||
| const build = await Bun.build({ | ||
| entrypoints: [join(dir, "c0.css")], | ||
| write: false, | ||
|
Check warning on line 56 in test/bundler/bun-build-api.test.ts
|
||
| }); | ||
|
|
||
| expect(build.success).toBe(true); | ||
| expect(build.outputs).toHaveLength(1); | ||
| expect(await build.outputs[0].text()).toContain(`.a${n - 1}`); | ||
| }); | ||
|
Check failure on line 62 in test/bundler/bun-build-api.test.ts
|
||
|
Comment on lines
+46
to
+62
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 This crash-regression test calls Extended reasoning...What the issue isThe new test REVIEW.md's Tests reviewers reject section states explicitly: "Crash fixes need the crashing input as a spawned fixture". This is listed among rules that have blocked merges. Step-by-step: how it manifests
Why nothing prevents itThere is no isolation here. In-file precedentThis file already encodes the correct pattern. The "loader map with an empty-string key" test carries this exact comment:
and spawns How to fixMove the test("css @import chain of 1000 files does not overflow the bundle thread stack", async () => {
const files: Record<string, string> = {};
const n = 1000;
for (let i = 0; i < n; i++) {
files[`c${i}.css`] = (i + 1 < n ? `@import "./c${i + 1}.css";\n` : "") + `.a${i} { color: red; }\n`;
}
const dir = tempDirWithFiles("bun-build-api-css-chain", files);
await using proc = Bun.spawn({
cmd: [
bunExe(),
"-e",
`
const build = await Bun.build({
entrypoints: [${JSON.stringify(join(dir, "c0.css"))}],
write: false,
});
if (!build.success) throw new AggregateError(build.logs, "build failed");
const text = await build.outputs[0].text();
console.log(JSON.stringify({ success: build.success, outputs: build.outputs.length, hasLast: text.includes(".a${n - 1}") }));
`,
],
env: bunEnv,
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
expect(stderr).toBe("");
expect(JSON.parse(stdout.trim())).toEqual({ success: true, outputs: 1, hasLast: true });
expect(exitCode).toBe(0);
});A regression then shows up as On the refutationOne verifier flagged bug_002 as a duplicate of bug_001. That is correct and is why these were merged into a single finding; it does not bear on whether the finding itself is real. |
||
|
|
||
| test("bytecode works", async () => { | ||
| const dir = tempDirWithFiles("bun-build-api-bytecode", { | ||
| "package.json": `{}`, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡
writeis not aBun.buildoption — it's not in theBuildConfiginterface (packages/bun-types/bun.d.ts) andJSBundler.rsnever reads it, so this line is a silently-ignored no-op that will fail typecheck against the published types. Bun.build already returns in-memory outputs wheneveroutdiris omitted (see the neighboring "css works" test), so just drop thewrite: falseline.Extended reasoning...
What the bug is
The new test at test/bundler/bun-build-api.test.ts:56 passes
write: falsetoBun.build(), butwriteis not a recognizedBuildConfigoption in Bun. This is an esbuild-ism — esbuild'sbuild()API useswrite: falseto request in-memory output instead of writing to disk, and the author likely copied the convention from there (test/js/third_party/esbuild/esbuild-test.js uses it for esbuild.build calls).The specific evidence
Not in the type definition: The
BuildConfiginterface in packages/bun-types/bun.d.ts (lines ~2899-3292) enumerates every accepted property —entrypoints,outdir,target,format,naming,splitting,plugins,external,define,loader,sourcemap,minify,bytecode,compile, etc. There is nowritefield.Not read at runtime: src/runtime/api/JSBundler.rs, which parses the
Bun.buildconfig object, contains ~39config.get*property reads. None of them reads a property named"write". The option is silently ignored — Bun.build does not perform excess-property validation on unknown keys.Explicitly documented as n/a: docs/bundler/esbuild.mdx:174 lists esbuild's
writeoption as "n/a" for Bun.build, with the note that output is in-memory wheneveroutdir/outfileis unset.Why the test still works
Bun.buildalready returns in-memoryBuildArtifactblobs whenever nooutdiris provided. The neighboring "css works" test at line 36 of the same file callsBun.buildwith onlyentrypointsandminify, then readsbuild.outputs[0].text()— nowriteoption needed. So the new test happens to work correctly, but only because thewrite: falseis dead: omittingoutdiris what actually produces the in-memory output.Impact
.d.ts(Object literal may only specify known properties, and 'write' does not exist in type 'BuildConfig').writeis a real Bun.build option and copy it elsewhere.Per REVIEW.md: "Every line you add must be demonstrably live … parsed-but-never-read is a red flag".
Step-by-step proof
Bun.build({ entrypoints: [join(dir, "c0.css")], write: false }).Bun.buildconfig parsing lives in src/runtime/api/JSBundler.rs. Grepping everyget_truthy/get_optional/ property-name string in that file yields no"write"— the property is never read off the config object.outdiris passed,JSBundlerleavesoptions.outdirempty, and the completion path returnsBuildArtifactblobs in memory (the same path the "css works" test on line 36 relies on).write: falseproduces byte-identical behavior; keeping it only adds a line that the runtime never reads and that TypeScript will flag againstBuildConfig.Fix
Delete line 56:
const build = await Bun.build({ entrypoints: [join(dir, "c0.css")], - write: false, });No
outdiralready means in-memory output.