When compile:true is used without an explicit target (or with
target:"browser" but non-HTML entrypoints), fall through to normal bun
executable compile instead of erroring. Standalone HTML mode only
activates when ALL entrypoints are .html files AND target is browser.
This preserves backward compatibility: compile:true alone still produces
a bun executable. The test harness defaults target to "browser", so
compile tests were breaking with the HTML-only validation.
Co-Authored-By: Claude <noreply@anthropic.com>
Instead of a separate --standalone flag, self-contained HTML output is
now triggered by --compile --target=browser (CLI) or compile: true with
target: "browser" (Bun.build API). This is more intuitive since --compile
already means "produce a single output" and --target=browser clarifies
what kind of output.
- Remove --standalone CLI flag and standalone Bun.build() option
- --compile --target=browser requires ALL entrypoints to be HTML files
- Rename internal option to compile_to_standalone_html for clarity
- When compile+browser is used, skip bun executable compile path
- Update TypeScript types and test suite
Co-Authored-By: Claude <noreply@anthropic.com>
Add `--standalone` CLI flag and `standalone: true` Bun.build() option
that produces self-contained HTML files with all JS, CSS, and assets
inlined directly into the HTML output.
- `<script src="...">` tags become `<script>` with bundled code inline
- `<link rel="stylesheet" href="...">` tags become `<style>` with CSS inline
- Asset references (images, fonts) become `data:` URIs
- CSS `url()` references become `data:` URIs (128KB threshold removed)
- Only HTML files are emitted, no separate JS/CSS/asset files
Validation:
- Errors if no HTML entrypoints are specified
- Errors if target is not browser
- Errors if --splitting is used
- Errors if --compile is used
This is useful for distributing .html files that work via file:// URLs
without needing a web server or worrying about CORS restrictions.
Co-Authored-By: Claude <noreply@anthropic.com>
Add `minify.unwrapCJSToESM` JS API option and `--unwrap-cjs-to-esm` CLI
flag to force CJS-to-ESM conversion for specific packages, eliminating
the `__commonJS` wrapper. Supports wildcard patterns (e.g. `"@scope/*"`).
User entries extend the default React family list.
Also removes the react/react-dom version check that gated conversion,
and fixes `packageName()` to handle scoped packages (`@scope/pkg`).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
### What does this PR do?
### How did you verify your code works?
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
## Summary
- Adds `--metafile-md` CLI option to `bun build` that generates a
markdown visualization of the module graph
- Designed to help Claude and other LLMs analyze bundle composition,
identify bloat, and understand dependency chains
- Reuses existing metafile JSON generation code as a post-processing
step
## Features
The generated markdown includes:
1. **Quick Summary** - Module counts, sizes, ESM/CJS breakdown,
output/input ratio
2. **Largest Input Files** - Sorted by size to identify potential bloat
3. **Entry Point Analysis** - Shows bundle size, exports, CSS bundles,
and bundled modules
4. **Dependency Chains** - Most commonly imported modules and reverse
dependencies
5. **Full Module Graph** - Complete import/export info for each module
6. **Raw Data for Searching** - Grep-friendly markers in code blocks:
- `[MODULE:]`, `[SIZE:]`, `[IMPORT:]`, `[IMPORTED_BY:]`
- `[ENTRY:]`, `[EXTERNAL:]`, `[NODE_MODULES:]`
## Usage
```bash
# Default filename (meta.md)
bun build entry.js --metafile-md --outdir=dist
# Custom filename
bun build entry.js --metafile-md=analysis.md --outdir=dist
# Both JSON and markdown
bun build entry.js --metafile=meta.json --metafile-md=meta.md --outdir=dist
```
## Example Output
See sample output: https://gist.github.com/example (will add)
## Test plan
- [x] Test default filename (`meta.md`)
- [x] Test custom filename
- [x] Test both `--metafile` and `--metafile-md` together
- [x] Test summary metrics
- [x] Test module format info (ESM/CJS)
- [x] Test external imports
- [x] Test exports list
- [x] Test bundled modules table
- [x] Test CSS bundle reference
- [x] Test import kinds (static, dynamic, require)
- [x] Test commonly imported modules
- [x] Test largest files sorting (bloat analysis)
- [x] Test output/input ratio
- [x] Test grep-friendly raw data section
- [x] Test entry point markers
- [x] Test external import markers
- [x] Test node_modules markers
All 17 new tests pass.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
## Summary
Adds a new CLI flag `--compile-executable-path` that allows specifying a
custom Bun executable path for cross-compilation instead of downloading
from the npm registry.
## Usage
```bash
bun build --compile --target=bun-linux-x64 \
--compile-executable-path=/path/to/bun-linux-x64 app.ts
```
## Motivation
The `executablePath` option was already available in the JavaScript
`Bun.build()` API. This exposes the same functionality from the CLI.
## Changes
- Added `--compile-executable-path <STR>` CLI parameter in
`src/cli/Arguments.zig`
- Added `compile_executable_path` field to `BundlerOptions` in
`src/cli.zig`
- Wired the option through to `StandaloneModuleGraph.toExecutable()` in
`src/cli/build_command.zig`
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
- Adds `import { feature } from "bun:bundle"` for compile-time feature
flag checking
- `feature("FLAG_NAME")` calls are replaced with `true`/`false` at
bundle time
- Enables dead-code elimination through `--feature=FLAG_NAME` CLI
argument
- Works in `bun build`, `bun run`, and `bun test`
- Available in both CLI and `Bun.build()` JavaScript API
## Usage
```ts
import { feature } from "bun:bundle";
if (feature("SUPER_SECRET")) {
console.log("Secret feature enabled!");
} else {
console.log("Normal mode");
}
```
### CLI
```bash
# Enable feature during build
bun build --feature=SUPER_SECRET index.ts
# Enable at runtime
bun run --feature=SUPER_SECRET index.ts
# Enable in tests
bun test --feature=SUPER_SECRET
```
### JavaScript API
```ts
await Bun.build({
entrypoints: ['./index.ts'],
outdir: './out',
features: ['SUPER_SECRET', 'ANOTHER_FLAG'],
});
```
## Implementation
- Added `bundler_feature_flags` (as `*const bun.StringSet`) to
`RuntimeFeatures` and `BundleOptions`
- Added `bundler_feature_flag_ref` to Parser struct to track the
`feature` import
- Handle `bun:bundle` import at parse time (similar to macros) - capture
ref, return empty statement
- Handle `feature()` calls in `e_call` visitor - replace with boolean
based on flags
- Wire feature flags through CLI arguments and `Bun.build()` API to
bundler options
- Added `features` option to `JSBundler.zig` for JavaScript API support
- Added TypeScript types in `bun.d.ts`
- Added documentation to `docs/bundler/index.mdx`
## Test plan
- [x] Basic feature flag enabled/disabled tests (both CLI and API
backends)
- [x] Multiple feature flags test
- [x] Dead code elimination verification tests
- [x] Error handling for invalid arguments
- [x] Runtime tests with `bun run --feature=FLAG`
- [x] Test runner tests with `bun test --feature=FLAG`
- [x] Aliased import tests (`import { feature as checkFeature }`)
- [x] Ternary operator DCE tests
- [x] Tests use `itBundled` with both `backend: "cli"` and `backend:
"api"`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Alistair Smith <hi@alistair.sh>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
## Summary
By default, standalone executables no longer load `tsconfig.json` and
`package.json` at runtime. This improves startup performance and
prevents unexpected behavior from config files in the runtime
environment.
- Added `--compile-autoload-tsconfig` / `--no-compile-autoload-tsconfig`
CLI flags (default: false)
- Added `--compile-autoload-package-json` /
`--no-compile-autoload-package-json` CLI flags (default: false)
- Added `autoloadTsconfig` and `autoloadPackageJson` options to the
`Bun.build()` compile config
- Flags are stored in `StandaloneModuleGraph.Flags` and applied at
runtime boot
This follows the same pattern as the existing
`--compile-autoload-dotenv` and `--compile-autoload-bunfig` flags.
## Test plan
- [x] Added tests in `test/bundler/bundler_compile_autoload.test.ts`
- [x] Verified standalone executables work correctly with runtime config
files that differ from compile-time configs
- [x] Verified the new CLI flags are properly parsed and applied
- [x] Verified the JS API options work correctly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Fixes#19652
## Summary
Fixes a crash that occurred when using the `--production` flag with `bun
build`, particularly on Windows where assertions are enabled in release
builds.
## Root Cause
The crash occurred because an assertion for `jsx.development` was
running **before** `jsx.development` was properly configured. The
problematic sequence was:
1. Set `NODE_ENV=production` in env map
2. Call `configureDefines()` which reads `NODE_ENV` and calls
`setProduction(true)`, setting `jsx.development=false`
3. ❌ **Assert `jsx.development` is false** (assertion fired here, before
line 203 below)
4. Set `jsx.development = !production` on line 203 (too late)
## Changes
This PR reorders the code to move the assertion **after**
`jsx.development` is properly set:
1. Set both `BUN_ENV` and `NODE_ENV` to `"production"` in env map
2. Call `configureDefines()`
3. Set `jsx.development = !production` (now happens first)
4. ✅ **Assert `jsx.development` is false** (now runs after it's set)
Also adds `BUN_ENV=production` to match the behavior of setting
`NODE_ENV`.
## Test Plan
Added regression test in `test/regression/issue/19652.test.ts` that
verifies `bun build --production` doesn't crash.
The test:
- ✅ Passes on this branch
- ❌ Would fail on main (assertion failure)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Fixes#23569
## Summary
HTML imports require bundling to work correctly, as they need to process
and transform linked assets (JS/CSS). When `--no-bundle` is used, no
bundling or transformation happens, which causes a crash.
This change adds validation to detect HTML entrypoints when
`--no-bundle` is used and provides a clear error message explaining that
"HTML imports are only supported when bundling".
## Changes
- Added validation in `src/cli/build_command.zig` to check for HTML
entrypoints when `--no-bundle` flag is used
- Shows clear error message: "HTML imports are only supported when
bundling"
- Added regression tests in `test/regression/issue/23569.test.ts`
## Test Plan
### Before
```bash
$ bun build ./index.html --no-bundle
# Crashes without helpful error
```
### After
```bash
$ bun build ./index.html --no-bundle
error: HTML imports are only supported when bundling
```
### Tests
- ✅ Test with `--no-bundle` flag errors correctly
- ✅ Test with `--no-bundle --outdir` errors correctly
- ✅ Test without `--no-bundle` works normally
- ✅ All 3 regression tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
- Removes unused function and class expression names when
`--minify-syntax` is enabled during bundling
- Adds `--keep-names` flag to preserve original names when minifying
- Matches esbuild's minification behavior
## Problem
When minifying with `--minify-syntax`, Bun was keeping function and
class expression names even when they were never referenced, resulting
in larger bundle sizes compared to esbuild.
**Before:**
```js
export var AB = function A() { };
// Bun output: var AB = function A() {};
// esbuild output: var AB = function() {};
```
## Solution
This PR adds logic to remove unused function and class expression names
during minification, matching esbuild's behavior. Names are only removed
when:
- `--minify-syntax` is enabled
- Bundling is enabled (not transform-only mode)
- The scope doesn't contain direct eval (which could reference the name
dynamically)
- The symbol's usage count is 0
Additionally, a `--keep-names` flag has been added to preserve original
names when desired (useful for debugging or runtime reflection).
## Testing
- Updated existing test in `bundler_minify.test.ts`
- All transpiler tests pass
- Manually verified output matches esbuild for various cases
## Examples
```bash
# Without --keep-names (names removed)
bun build --minify-syntax input.js
# var AB = function() {}
# With --keep-names (names preserved)
bun build --minify-syntax --keep-names input.js
# var AB = function A() {}
```
🤖 Generated with [Claude Code](https://claude.ai/code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
### What does this PR do?
in the name
### How did you verify your code works?
tests, but using ci to see if anything else broke
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
## Summary
This PR adds a new `--compile-argv` option to `bun build --compile` that
allows developers to embed runtime arguments into standalone
executables. The specified arguments are stored in the executable
metadata during compilation and provide **dual functionality**:
1. **🔧 Actually processed by Bun runtime** (like passing them on command
line)
2. **📊 Available in `process.execArgv`** (for application inspection)
This means flags like `--user-agent`, `--smol`, `--max-memory` will
actually take effect AND be visible to your application!
## Motivation & Use Cases
### 1. **Global User Agent for Web Scraping**
Perfect for @thdxr's opencode use case - the user agent actually gets
applied:
```bash
# Compile with custom user agent that ACTUALLY works
bun build --compile --compile-argv="--user-agent='OpenCode/1.0'" ./scraper.ts --outfile=opencode
# The user agent is applied by Bun runtime AND visible in execArgv
./opencode # All HTTP requests use the custom user agent!
```
### 2. **Memory-Optimized Builds**
Create builds with actual runtime memory optimizations:
```bash
# Compile with memory optimization that ACTUALLY takes effect
bun build --compile --compile-argv="--smol --max-memory=512mb" ./app.ts --outfile=app-optimized
# Bun runtime actually runs in smol mode with memory limit
```
### 3. **Performance & Debug Builds**
Different builds with different runtime characteristics:
```bash
# Production: optimized for memory
bun build --compile --compile-argv="--smol --gc-frequency=high" ./app.ts --outfile=app-prod
# Debug: with inspector enabled
bun build --compile --compile-argv="--inspect=0.0.0.0:9229" ./app.ts --outfile=app-debug
```
### 4. **Security & Network Configuration**
Embed security settings that actually apply:
```bash
# TLS and network settings that work
bun build --compile --compile-argv="--tls-min-version=1.3 --dns-timeout=5000" ./secure-app.ts
```
## How It Works
### Dual Processing Architecture
The implementation provides both behaviors:
```bash
# Compiled with: --compile-argv="--smol --user-agent=Bot/1.0"
./my-app --config=prod.json
```
**What happens:**
1. **🔧 Runtime Processing**: Bun processes `--smol` and
`--user-agent=Bot/1.0` as if passed on command line
2. **📊 Application Access**: Your app can inspect these via
`process.execArgv`
```javascript
// In your compiled application:
// 1. The flags actually took effect:
// - Bun is running in smol mode (--smol processed)
// - All HTTP requests use Bot/1.0 user agent (--user-agent processed)
// 2. You can also inspect what flags were used:
console.log(process.execArgv); // ["--smol", "--user-agent=Bot/1.0"]
console.log(process.argv); // ["./my-app", "--config=prod.json"]
// 3. Your application logic can adapt:
if (process.execArgv.includes("--smol")) {
console.log("Running in memory-optimized mode");
}
```
### Implementation Details
1. **Build Time**: Arguments stored in executable metadata
2. **Runtime Startup**:
- Arguments prepended to actual argv processing (so Bun processes them)
- Arguments also populate `process.execArgv` (so app can inspect them)
3. **Result**: Flags work as if passed on command line + visible to
application
## Example Usage
```bash
# User agent that actually works
bun build --compile --compile-argv="--user-agent='MyBot/1.0'" ./scraper.ts --outfile=scraper
# Memory optimization that actually applies
bun build --compile --compile-argv="--smol --max-memory=256mb" ./microservice.ts --outfile=micro
# Debug build with working inspector
bun build --compile --compile-argv="--inspect=127.0.0.1:9229" ./app.ts --outfile=app-debug
# Multiple working flags
bun build --compile --compile-argv="--smol --user-agent=Bot/1.0 --tls-min-version=1.3" ./secure-scraper.ts
```
## Runtime Verification
```javascript
// Check what runtime flags are active
const hasSmol = process.execArgv.includes("--smol");
const userAgent = process.execArgv.find(arg => arg.startsWith("--user-agent="))?.split("=")[1];
const maxMemory = process.execArgv.find(arg => arg.startsWith("--max-memory="))?.split("=")[1];
console.log("Memory optimized:", hasSmol);
console.log("User agent:", userAgent);
console.log("Memory limit:", maxMemory);
// These flags also actually took effect in the runtime!
```
## Changes Made
### Core Implementation
- **Arguments.zig**: Added `--compile-argv <STR>` flag with validation
- **StandaloneModuleGraph.zig**: Serialization/deserialization for
`compile_argv`
- **build_command.zig**: Pass `compile_argv` to module graph
- **cli.zig**: **Prepend arguments to actual argv processing** (so Bun
processes them)
- **node_process.zig**: **Populate `process.execArgv`** from stored
arguments
- **bun.zig**: Made `appendOptionsEnv()` public for reuse
### Testing
- **expectBundled.ts**: Added `compileArgv` test support
- **compile-argv.test.ts**: Tests verifying dual behavior
## Behavior
### Complete Dual Functionality
```javascript
// With --compile-argv="--smol --user-agent=TestBot/1.0":
// ✅ Runtime flags actually processed by Bun:
// - Memory usage optimized (--smol effect)
// - HTTP requests use TestBot/1.0 user agent (--user-agent effect)
// ✅ Flags visible to application:
process.execArgv // ["--smol", "--user-agent=TestBot/1.0"]
process.argv // ["./app", ...script-args] (unchanged)
```
## Backward Compatibility
- ✅ Purely additive feature - no breaking changes
- ✅ Optional flag - existing behavior unchanged when not used
- ✅ No impact on non-compile builds
## Perfect for @thdxr's Use Case!
```bash
# Compile opencode with working user agent
bun build --compile --compile-argv="--user-agent='OpenCode/1.0'" ./opencode.ts --outfile=opencode
# Results in:
# 1. All HTTP requests actually use OpenCode/1.0 user agent ✨
# 2. process.execArgv contains ["--user-agent=OpenCode/1.0"] for inspection ✨
```
The user agent will actually work in all HTTP requests made by the
compiled executable, not just be visible as metadata!
🚀 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude <claude@anthropic.ai>
### What does this PR do?
The `then` function in `transpiler.transform` can cause GC, which means
it can cause the `Transpiler` to become freed, which means that if that
same transpiler is in use by another run on the other thread, it could
have pointers to invalid memory.
Also, `ESMCondition` has unnecesasry memory allocations and there is a
very tiny memory leak in optionsFromLoaders
### How did you verify your code works?
Existing tests
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>