Repository navigation
Conversation
… of the CLI context `bun repl` moved `ctx.args` out of the process-global CLI context when it booted its VM. `Bun.serve` HTML routes read `serve_minify_*`, `serve_define` and `serve_sourcemap` from that context when they build, so inside the REPL the `[serve.static]` table of bunfig.toml had no minify, define or sourcemap keys. The REPL now clones the options, as `bun run`, `bun test` and the bake production build do.
|
Updated 11:31 PM PT - Oct 20th, 2026
✅ @robobun, your commit 9949e3aac5893674f4e996461bea673afe7c5314 passed in 🧪 To try this PR locally: bunx bun-pr 46264That installs a local version of the PR into your bun-46264 --bun |
|
Status Reproduced on 1.4.2, on 1.4.3-canary.1 (367d939) and on a debug build of main (ea6a2c7). Bun 1.3.13 does not have the bug. cat > bunfig.toml <<'TOML'
[serve.static]
minify = false
sourcemap = "linked"
[serve.static.define]
BUILD_FLAG = '"from-bunfig"'
TOML
echo '<!doctype html><html><body><script type="module" src="./app.ts"></script></body></html>' > index.html
echo 'function describeTheFlag(flag: string) { return flag === undefined ? "none" : "MARKER " + flag; } console.log(describeTheFlag(BUILD_FLAG));' > app.ts
cat > serve.ts <<'TS'
import index from "./index.html";
const server = Bun.serve({ port: 0, development: false, routes: { "/": index } });
const html = await (await fetch(server.url)).text();
const jsPath = html.split('src="')[1].split('"')[0];
console.log(await (await fetch(new URL(jsPath, server.url))).text());
console.log((await fetch(new URL(jsPath + ".map", server.url))).status);
await server.stop(true);
TS
bun serve.ts # unminified, "from-bunfig", sourceMappingURL comment, 200
bun repl -e "$(cat serve.ts)" # function t(e){...}console.log(t(BUILD_FLAG)); 404With this PR the second command prints the same chunk and status as the first. CI. Buildkite build #129746 passed: 183 of 183 jobs. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
WalkthroughREPL VM initialization now clones command arguments before passing them to ChangesREPL argument preservation and static-serving configuration
Suggested reviewers: Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to
|
There was a problem hiding this comment.
Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.
LGTM — a one-line change that brings bun repl in line with how bun run and bun test already hand ctx.args to the VM, with a test matrix that covers the REPL entry points alongside the bun <file> reference. Beyond the inline note, I checked that no other core::mem::take(&mut ctx.args) site remains in src/ and that HTMLBundle.rs:424-476 is the consumer reading Command::get().args after boot, so the comment is accurate.
Extended reasoning...
The diff replaces core::mem::take(&mut ctx.args) with ctx.args.clone() in ReplCommand::boot_repl_vm (src/runtime/cli/repl_command.rs:81) plus a one-line why-comment, and adds a serial describe block to test/js/bun/http/bun-serve-html.test.ts with six cases (two bunfig modes times three entry points) that assert exact minify/define/sourcemap outcomes and drain stdout/stderr concurrently. It touches no security-sensitive surface. The pattern already exists at run_command.rs:1040 and test_command.rs:1957, no mem::take(&mut ctx.args) sibling remains, the consumer at HTMLBundle.rs:424 is real, and no CODEOWNERS entry covers the changed files. The single inline finding is a pre-existing --smol/mini_mode omission the author explicitly scoped out, not something this PR introduces.
Problem
bun repl, aBun.serveHTML route built without the HMR dev server ignoresminify,defineandsourcemapfrom bunfig[serve.static].bun file.tshonors them.argsin the process-global CLI context:core::mem::take(&mut ctx.args)(src/runtime/cli/repl_command.rs:80).Route::on_plugins_resolved(src/runtime/server/HTMLBundle.rs:424) reads those keys there and findsNone.Fix
ctx.args.clone()), likebun run,bun test, standalone executables and the bake build. The global keeps its values.test/js/bun/http/bun-serve-html.test.ts(6 new cases, 4 fail on 1.4.3 and on main). Also ranrepl.test.ts,bake/dev-and-prod.test.ts.--smolgap in Notes.Background
ContextData. A command's main VM boots with a copy of itsargs.publicPathandenvfrom the VM copy and the three keys above from the global, so the REPL honored only the first two.Downsides
bun replprocess: +3 allocations (56 B) and +635 instructions in an empty directory. With the table from Notes: +8 allocations (136 B) and +984 instructions.bun -e 1makes 4436 allocator calls before and after.Notes
Trigger. All of these at once:
bun repl, an HTML import as aBun.serveroute, a mode without the HMR dev server (development: false,development: { hmr: false }orNODE_ENV=production), andminify,defineorsourcemapin[serve.static]. The default mode is not affected: the HMR dev server readsserve_definefrom the VM copy (src/runtime/server/ServerConfig.rs:956).bun file.tsandbun -eare not affected. A read of the port found this. No user reported it.Repro.
bunfig.toml:index.htmlloadsapp.ts(function describeTheFlag(flag: string) { return flag === undefined ? "none" : "MARKER " + flag; } console.log(describeTheFlag(BUILD_FLAG));).serve.tsserves the page withBun.serve({ port: 0, development: false, routes: { "/": index } }), fetches the script chunk and its.map, and prints both.bun serve.tsandbun -e "$(cat serve.ts)": the chunk keepsdescribeTheFlag, holds"from-bunfig"and asourceMappingURLcomment, and the.maprequest answers 200.bun repl -e "$(cat serve.ts)"on 1.4.3:function t(e){return e===void 0?"none":"MARKER "+e}console.log(t(BUILD_FLAG));, and the.maprequest answers 404.development: { hmr: false },minify = trueandsourcemap = "none"the REPL does the opposite: an unminified chunk, a bareBUILD_FLAG, and a sourcemap that the table turned off.History.
git show d4514457e8^:src/runtime/cli/repl_command.zigline 44 is.args = ctx.args, a struct copy.src/runtime/cli/test_command.rs:1952has the sameClone (not take)comment for the same reason: a later reader ofctx.args.Tests. The new
describeruns one script in three ways:bun serve.ts,bun repl -e, andbun replwith the script typed on stdin. It has two modes:development: falsewithminify = falseandsourcemap = "linked", anddevelopment: { hmr: false }withminify = trueandsourcemap = "none". The 2bun serve.tscases pass before and after. They pin the reference that the REPL must match, and they are the first test of[serve.static] minifyanddefineoutside the REPL. The 4 REPL cases fail without the fix. The cases are serial because six debug ASAN processes at once take about 4 s on a 12-core machine, close to the 5 s limit. The script has no quote inside a regex literal, because the REPL line reader takes it for an open string (#37326, fix in #37327).The interactive prompt. At an idle prompt the REPL does not run the event loop (#30559). A server that a prompt line starts answers only while a line awaits a promise, or from a
Worker. The stdin cases await each request, so they use the first path. This PR does not change #30559.Also checked by hand on the debug build.
bun repl -p, aBun.serveinside aWorkerstarted frombun repl -e, and a route added withserver.reload()in the REPL. All three ignore the table on 1.4.3 and honor it with the fix. They read the same context.Measurements. Release builds (ThinLTO) of
ea6a2c7b7c, three commits before the base of this branch, with and without the one line. Counts come from gdb breakpoints and single-steps onbun-profile, becausevalgrind,perf,straceandbloatyare not installed in the build container. Each allocator total was identical across 3 runs.bun repl -e 1TransformOptions::clonecallsArena::new()to the call ofVirtualMachine::init, empty directorybun repl -e 1runs about 4.07 million user instructions (perf_event_open, 21 interleaved pairs). The count varies by about 30,000 between identical runs, so it cannot resolve the change. That is why the hand-off was counted by single-step.bun -e 1: 4436 allocator calls and 2TransformOptions::clonecalls, before and after.size: text 107,094,878 B to 107,094,622 B. data and bss do not change. Of 139,012 symbols onlyReplCommand::execchanges size (5686 B to 5366 B).RunCommand::boot_main,create_context_data,init_runtime_stateandRoute::on_plugins_resolveddisassemble to the same instructions.Not changed here.
runtime_options.debugger,preloads,passthroughandeval.interactive_scriptinrepl_command.rs,run_command.rsandtest_command.rs, andargs.serve_pluginsandargs.bunfig_pathin standalone executables (run_command.rs:1292). Nothing reads those through the global context after the boot. To clone them would add allocations to everybun runfor no change in behavior.on_plugins_resolvedstill reads from two places.HTMLBundle.rsis not touched, so Apply CLI and bunfig define to HTML bundles served by Bun.serve #40485 does not need a rebase, and its new read of the context works in the REPL.repl_command.rs:80and still has themem::take. A rebase of either PR must keep the clone. The new test fails if it does not. repl: run --preload / -r / --require / --import before the first evaluation #46160 edits the same function below that line and does not conflict.smolwithoutmini_mode(repl_command.rs:85, comparerun_command.rs:1044), so--smoldoes not select the small JSC heap inbun repl. A loop that makes garbage peaks at about 41 MB underbun --smol -eand at about 50 MB underbun repl --smol -e, the same as without the flag.test_command.rs:1961omitsmini_modetoo. It needs its own fix and test.