Repository navigation
Conversation
`bun build --help` documents `--production` as "Set NODE_ENV=production", but the flag was implemented as a default rather than an override: the NODE_ENV write happened before load_process() ingested the real process environment into the same map, so an ambient NODE_ENV=development (common in dev shells and CI test jobs) silently won and the bundle inlined process.env.NODE_ENV as "development". Set options.production and options.force_node_env = Production when the flag is passed, and teach load_defines to honor force_node_env ahead of the env loader. An explicit --define process.env.NODE_ENV=... still wins over the flag.
WalkthroughAdds ChangesForce production NODE_ENV
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
|
Updated 12:08 PM PT - Jul 9th, 2026
❌ @robobun, your commit 2371f63 has 4 failures in
🧪 To try this PR locally: bunx bun-pr 33855That installs a local version of the PR into your bun-33855 --bun |
|
Found 3 issues this PR may fix:
🤖 Generated with Claude Code |
get_node_env() consults BUN_ENV before NODE_ENV, so an ambient BUN_ENV=test would still leak through for .env suffix selection. Write both after load_process() and extend the test matrix to cover the BUN_ENV alias.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/bundler/transpiler.rs`:
- Around line 739-742: The DotEnvBehavior::disable branch in
transpiler::load_defines is missing the same forced NODE_ENV/BUN_ENV reassertion
used in the prefix/load_all paths. After load_process() and the force_node_env
== Production check, update env.map in the disable arm too so
env.get(b"NODE_ENV") and env.get(b"BUN_ENV") stay set to production for all
consumers. Use the existing load_process()/force_node_env logic in load_defines
as the reference point and mirror the env.map.put behavior there.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: cebf466b-ab78-45c3-80f0-0deba402bd57
📒 Files selected for processing (4)
src/bundler/options.rssrc/bundler/transpiler.rssrc/runtime/cli/build_command.rstest/bundler/bundler_edgecase.test.ts
There was a problem hiding this comment.
My earlier feedback (BUN_ENV sibling) and CodeRabbit's (disable arm) are both addressed and the change looks correct, but this is a user-visible precedence change to --production and the bundler's define/env resolution — worth a quick human sign-off.
Extended reasoning...
Overview
This PR changes bun build --production so it overrides an ambient NODE_ENV/BUN_ENV in the process environment instead of merely defaulting it. Touched files:
src/runtime/cli/build_command.rs— under--production, callset_production(true)and setforce_node_env = Productionon both bundler and resolver options beforeconfigure_defines().src/bundler/options.rs—load_defines()now short-circuits onforce_node_envbefore consulting the env loader forprocess.env.NODE_ENV.src/bundler/transpiler.rs— afterload_process()in both theprefix|load_all|...anddisablearms ofrun_env_loader(), re-assertNODE_ENV=productionandBUN_ENV=productionin the env map whenforce_node_env == Production.test/bundler/bundler_edgecase.test.ts— a 2×5itBundledmatrix (NODE_ENV/BUN_ENV× unset/production/development/test/empty) plus a--define-still-wins case.
Security risks
None identified. No auth, crypto, permissions, or untrusted-input parsing is touched; the change only adjusts which build-time constant is inlined for process.env.NODE_ENV and which .env.* suffix is loaded.
Level of scrutiny
Moderate. This is a user-visible semantic change to the precedence of --production vs ambient env in production builds — arguably a bugfix (behavior now matches --help and docs), but it does alter output for anyone who was relying on ambient NODE_ENV winning. It also threads through force_node_env, which fans out to jsx.development in bundle_v2.rs and gates set_production() (options.rs:1436). I traced call ordering in build_command.rs — set_production(true) runs while force_node_env is still Unspecified, then force_node_env is locked, so production=true is actually applied; downstream set_production calls in run_env_loader become no-ops, which is the intent. The later explicit jsx.development = false under --production is unchanged, so JSX behavior is preserved.
Other factors
- My prior inline review flagged the
BUN_ENVsibling; addressed in f508f1d with the test matrix extended to cover it. CodeRabbit'sDotEnvBehavior::disablemirror was addressed in 94db7a1. All threads resolved. - No CODEOWNERS entries for these paths.
- Tests follow the existing
itBundledconventions inbundler_edgecase.test.tsand include a negative check that--definestill wins. - Bug-hunting system found no issues on the latest revision.
Not approving solo because this is a deliberate behavior/precedence change to a core bundler flag rather than a mechanical fix; a maintainer should confirm the new precedence (--define > --production > ambient env > default) is the intended contract.
|
The diff is green. The new bundler tests pass on all lanes. Remaining CI failures are unrelated Windows flakes (also seen on other branches, e.g. build 71081):
Neither touches the bundler or env-loading paths in this change. Ready for review. |
|
Closing this PR because it has been inactive for more than 90 days. |
|
Superseded by #45101. It fixes the same bug on current main with a different mechanism: the flag writes |
What does this PR do?
bun build --helpdocuments--productionas "Set NODE_ENV=production and enable minification", and the bundler docs say the flag "Setsprocess.env.NODE_ENVtoproduction". But the flag was implemented as a default rather than an override, so an ambientNODE_ENVin the build process environment (common in dev shells and CI test jobs) silently won and the bundle inlined the wrong value.Repro
Observed precedence before this change:
Cause
build_command.rswroteNODE_ENV=productioninto the dotenv loader's map beforeconfigure_defines()ranload_process(), which then overwrote that entry from the real process environment.load_defines()insrc/bundler/options.rsconsults the env loader first and only falls back toself.productionwhen the loader has noNODE_ENVat all.Fix
--productionis passed, setoptions.production = trueandoptions.force_node_env = ForceNodeEnv::Productionbeforeconfigure_defines(), so the flag's intent survives env loading.load_defines()now honorsforce_node_envahead of the env loader when resolving theprocess.env.NODE_ENVdefine.run_env_loader()re-assertsNODE_ENV=productionin the env map afterload_process()whenforce_node_envisProduction, so.env.production(not.env.test/.env.development) is loaded when--envis also passed.New precedence:
An explicit
--define process.env.NODE_ENV=...still wins over--production(covered by a test).This also fixes a secondary symptom: with an ambient
NODE_ENV=development,bun build --productionwas appending the"development"export condition, pulling in dev-only package entries.How did you verify your code works?
Added
itBundledtests intest/bundler/bundler_edgecase.test.tscovering--productionwith ambientNODE_ENVunset /production/development/test/ empty, plus a test asserting--definestill wins.Fail-before (system bun):
development/test/empty cases fail with"development"/"test"in the bundle.Pass-after (
bun bd test): all 6 pass; full edgecase suite (116 tests) green.no test proof · iteration 1 · Platform-specific test(s) that do not run on this machine. Deferring to CI, which covers all platforms: test/bundler/bundler_edgecase.test.ts