mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
feat(bundler): add statically-analyzable dead-code elimination via feature flags (#25462)
## 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>
This commit is contained in:
18
packages/bun-types/bun.d.ts
vendored
18
packages/bun-types/bun.d.ts
vendored
@@ -1891,6 +1891,24 @@ declare module "bun" {
|
||||
*/
|
||||
drop?: string[];
|
||||
|
||||
/**
|
||||
* Enable feature flags for dead-code elimination via `import { feature } from "bun:bundle"`.
|
||||
*
|
||||
* When `feature("FLAG_NAME")` is called, it returns `true` if FLAG_NAME is in this array,
|
||||
* or `false` otherwise. This enables static dead-code elimination at bundle time.
|
||||
*
|
||||
* Equivalent to the CLI `--feature` flag.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* await Bun.build({
|
||||
* entrypoints: ['./src/index.ts'],
|
||||
* features: ['FEATURE_A', 'FEATURE_B'],
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
features?: string[];
|
||||
|
||||
/**
|
||||
* - When set to `true`, the returned promise rejects with an AggregateError when a build failure happens.
|
||||
* - When set to `false`, returns a {@link BuildOutput} with `{success: false}`
|
||||
|
||||
74
packages/bun-types/bundle.d.ts
vendored
Normal file
74
packages/bun-types/bundle.d.ts
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* The `bun:bundle` module provides compile-time utilities for dead-code elimination.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { feature } from "bun:bundle";
|
||||
*
|
||||
* if (feature("SUPER_SECRET")) {
|
||||
* console.log("Secret feature enabled!");
|
||||
* } else {
|
||||
* console.log("Normal mode");
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Enable feature flags via CLI:
|
||||
* ```bash
|
||||
* # During build
|
||||
* bun build --feature=SUPER_SECRET index.ts
|
||||
*
|
||||
* # At runtime
|
||||
* bun run --feature=SUPER_SECRET index.ts
|
||||
*
|
||||
* # In tests
|
||||
* bun test --feature=SUPER_SECRET
|
||||
* ```
|
||||
*
|
||||
* @module bun:bundle
|
||||
*/
|
||||
declare module "bun:bundle" {
|
||||
/**
|
||||
* Registry for type-safe feature flags.
|
||||
*
|
||||
* Augment this interface to get autocomplete and type checking for your feature flags:
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // env.d.ts
|
||||
* declare module "bun:bundle" {
|
||||
* interface Registry {
|
||||
* features: "DEBUG" | "PREMIUM" | "BETA";
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Now `feature()` only accepts `"DEBUG"`, `"PREMIUM"`, or `"BETA"`:
|
||||
* ```ts
|
||||
* feature("DEBUG"); // OK
|
||||
* feature("TYPO"); // Type error
|
||||
* ```
|
||||
*/
|
||||
interface Registry {}
|
||||
|
||||
/**
|
||||
* Check if a feature flag is enabled at compile time.
|
||||
*
|
||||
* This function is replaced with a boolean literal (`true` or `false`) at bundle time,
|
||||
* enabling dead-code elimination. The bundler will remove unreachable branches.
|
||||
*
|
||||
* @param flag - The name of the feature flag to check
|
||||
* @returns `true` if the flag was passed via `--feature=FLAG`, `false` otherwise
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { feature } from "bun:bundle";
|
||||
*
|
||||
* // With --feature=DEBUG, this becomes: if (true) { ... }
|
||||
* // Without --feature=DEBUG, this becomes: if (false) { ... }
|
||||
* if (feature("DEBUG")) {
|
||||
* console.log("Debug mode enabled");
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
function feature(flag: Registry extends { features: infer Features extends string } ? Features : string): boolean;
|
||||
}
|
||||
1
packages/bun-types/index.d.ts
vendored
1
packages/bun-types/index.d.ts
vendored
@@ -23,6 +23,7 @@
|
||||
/// <reference path="./serve.d.ts" />
|
||||
/// <reference path="./sql.d.ts" />
|
||||
/// <reference path="./security.d.ts" />
|
||||
/// <reference path="./bundle.d.ts" />
|
||||
|
||||
/// <reference path="./bun.ns.d.ts" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user