Compare commits

...

1 Commits

Author SHA1 Message Date
Claude Bot
4a4edae9ad Add NODE_OPTIONS environment variable support
This adds support for the NODE_OPTIONS environment variable, which works
as a fallback to BUN_OPTIONS. This improves Node.js compatibility by
allowing users and tools to set command-line options via NODE_OPTIONS,
which is a standard Node.js feature.

Implementation:
- Added NODE_OPTIONS to src/env_var.zig
- Updated src/bun.zig to check BUN_OPTIONS first, then fall back to
  NODE_OPTIONS using the orelse operator
- BUN_OPTIONS takes precedence when both are set
- Added comprehensive tests for NODE_OPTIONS behavior
- Updated documentation to explain the relationship between the two

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-29 09:59:04 +00:00
4 changed files with 64 additions and 1 deletions

View File

@@ -225,6 +225,11 @@ These environment variables are read by Bun and configure aspects of its behavio
- `BUN_OPTIONS`
- Prepends command-line arguments to any Bun execution. For example, `BUN_OPTIONS="--hot"` makes `bun run dev` behave like `bun --hot run dev`.
---
- `NODE_OPTIONS`
- Works identically to `BUN_OPTIONS`. Prepends command-line arguments to any Bun execution. If both `BUN_OPTIONS` and `NODE_OPTIONS` are set, `BUN_OPTIONS` takes precedence. This provides compatibility with Node.js tooling.
{% /table %}
## Runtime transpiler caching

View File

@@ -2208,7 +2208,7 @@ pub fn initArgv(allocator: std.mem.Allocator) !void {
argv = try std.process.argsAlloc(allocator);
}
if (bun.env_var.BUN_OPTIONS.get()) |opts| {
if (bun.env_var.BUN_OPTIONS.get() orelse bun.env_var.NODE_OPTIONS.get()) |opts| {
var argv_list = std.ArrayList([:0]const u8).fromOwnedSlice(allocator, argv);
try appendOptionsEnv(opts, &argv_list, allocator);
argv = argv_list.items;

View File

@@ -99,6 +99,7 @@ pub const MI_VERBOSE = New(kind.boolean, "MI_VERBOSE", .{ .default = false });
pub const NO_COLOR = New(kind.boolean, "NO_COLOR", .{ .default = false });
pub const NODE = New(kind.string, "NODE", .{});
pub const NODE_CHANNEL_FD = New(kind.string, "NODE_CHANNEL_FD", .{});
pub const NODE_OPTIONS = New(kind.string, "NODE_OPTIONS", .{});
pub const NODE_PRESERVE_SYMLINKS_MAIN = New(kind.boolean, "NODE_PRESERVE_SYMLINKS_MAIN", .{ .default = false });
pub const NODE_USE_SYSTEM_CA = New(kind.boolean, "NODE_USE_SYSTEM_CA", .{ .default = false });
pub const npm_lifecycle_event = New(kind.string, "npm_lifecycle_event", .{});

View File

@@ -69,3 +69,60 @@ describe("BUN_OPTIONS environment variable", () => {
expect(result.stdout.toString()).toContain("NORMAL");
});
});
describe("NODE_OPTIONS environment variable", () => {
test("basic usage - passes options to bun command", () => {
const result = spawnSync({
cmd: [bunExe()],
env: {
...bunEnv,
NODE_OPTIONS: "--print='NODE_OPTIONS WAS A SUCCESS'",
},
});
expect(result.exitCode).toBe(0);
expect(result.stdout.toString()).toContain("NODE_OPTIONS WAS A SUCCESS");
});
test("multiple options - passes all options to bun command", () => {
const result = spawnSync({
cmd: [bunExe()],
env: {
...bunEnv,
NODE_OPTIONS: "--print='MULTIPLE OPTIONS' --quiet",
},
});
expect(result.exitCode).toBe(0);
expect(result.stdout.toString()).toContain("MULTIPLE OPTIONS");
});
test("BUN_OPTIONS takes precedence over NODE_OPTIONS", () => {
const result = spawnSync({
cmd: [bunExe()],
env: {
...bunEnv,
NODE_OPTIONS: "--print='NODE'",
BUN_OPTIONS: "--print='BUN'",
},
});
expect(result.exitCode).toBe(0);
expect(result.stdout.toString()).toContain("BUN");
expect(result.stdout.toString()).not.toContain("NODE");
});
test("NODE_OPTIONS works when BUN_OPTIONS is not set", () => {
const result = spawnSync({
cmd: [bunExe()],
env: {
...bunEnv,
NODE_OPTIONS: "--print='FALLBACK TO NODE_OPTIONS'",
BUN_OPTIONS: undefined,
},
});
expect(result.exitCode).toBe(0);
expect(result.stdout.toString()).toContain("FALLBACK TO NODE_OPTIONS");
});
});