Skip to content

Commit 23383b3

Browse files
robobunClaude BotclaudeJarred-Sumner
authored
feat(compile): add --compile-autoload-tsconfig and --compile-autoload-package-json flags (#25340)
## 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 <[email protected]> Co-authored-by: Claude <[email protected]> Co-authored-by: Jarred Sumner <[email protected]>
1 parent 0d5a7c3 commit 23383b3

File tree

11 files changed

+322
-22
lines changed

11 files changed

+322
-22
lines changed

src/StandaloneModuleGraph.zig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,9 @@ pub const StandaloneModuleGraph = struct {
296296
pub const Flags = packed struct(u32) {
297297
disable_default_env_files: bool = false,
298298
disable_autoload_bunfig: bool = false,
299-
_padding: u30 = 0,
299+
disable_autoload_tsconfig: bool = false,
300+
disable_autoload_package_json: bool = false,
301+
_padding: u28 = 0,
300302
};
301303

302304
const trailer = "\n---- Bun! ----\n";

src/bun.js.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ pub const Run = struct {
9090
b.options.env.behavior = .load_all_without_inlining;
9191
}
9292

93+
// Control loading of tsconfig.json and package.json at runtime
94+
// By default, these are disabled for standalone executables
95+
b.resolver.opts.load_tsconfig_json = !graph.flags.disable_autoload_tsconfig;
96+
b.resolver.opts.load_package_json = !graph.flags.disable_autoload_package_json;
97+
9398
b.configureDefines() catch {
9499
failWithBuildError(vm);
95100
};

src/bun.js/api/JSBundler.zig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ pub const JSBundler = struct {
5959
outfile: OwnedString = OwnedString.initEmpty(bun.default_allocator),
6060
autoload_dotenv: bool = true,
6161
autoload_bunfig: bool = true,
62+
autoload_tsconfig: bool = false,
63+
autoload_package_json: bool = false,
6264

6365
pub fn fromJS(globalThis: *jsc.JSGlobalObject, config: jsc.JSValue, allocator: std.mem.Allocator, compile_target: ?CompileTarget) JSError!?CompileOptions {
6466
var this = CompileOptions{
@@ -187,6 +189,14 @@ pub const JSBundler = struct {
187189
this.autoload_bunfig = autoload_bunfig;
188190
}
189191

192+
if (try object.getBooleanLoose(globalThis, "autoloadTsconfig")) |autoload_tsconfig| {
193+
this.autoload_tsconfig = autoload_tsconfig;
194+
}
195+
196+
if (try object.getBooleanLoose(globalThis, "autoloadPackageJson")) |autoload_package_json| {
197+
this.autoload_package_json = autoload_package_json;
198+
}
199+
190200
return this;
191201
}
192202

src/bundler/bundle_v2.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2045,6 +2045,8 @@ pub const BundleV2 = struct {
20452045
.{
20462046
.disable_default_env_files = !compile_options.autoload_dotenv,
20472047
.disable_autoload_bunfig = !compile_options.autoload_bunfig,
2048+
.disable_autoload_tsconfig = !compile_options.autoload_tsconfig,
2049+
.disable_autoload_package_json = !compile_options.autoload_package_json,
20482050
},
20492051
) catch |err| {
20502052
return bun.StandaloneModuleGraph.CompileResult.failFmt("{s}", .{@errorName(err)});

src/cli.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,8 @@ pub const Command = struct {
461461
compile_exec_argv: ?[]const u8 = null,
462462
compile_autoload_dotenv: bool = true,
463463
compile_autoload_bunfig: bool = true,
464+
compile_autoload_tsconfig: bool = false,
465+
compile_autoload_package_json: bool = false,
464466
windows: options.WindowsOptions = .{},
465467
};
466468

src/cli/Arguments.zig

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ pub const build_only_params = [_]ParamType{
153153
clap.parseParam("--no-compile-autoload-dotenv Disable autoloading of .env files in standalone executable") catch unreachable,
154154
clap.parseParam("--compile-autoload-bunfig Enable autoloading of bunfig.toml in standalone executable (default: true)") catch unreachable,
155155
clap.parseParam("--no-compile-autoload-bunfig Disable autoloading of bunfig.toml in standalone executable") catch unreachable,
156+
clap.parseParam("--compile-autoload-tsconfig Enable autoloading of tsconfig.json at runtime in standalone executable (default: false)") catch unreachable,
157+
clap.parseParam("--no-compile-autoload-tsconfig Disable autoloading of tsconfig.json at runtime in standalone executable") catch unreachable,
158+
clap.parseParam("--compile-autoload-package-json Enable autoloading of package.json at runtime in standalone executable (default: false)") catch unreachable,
159+
clap.parseParam("--no-compile-autoload-package-json Disable autoloading of package.json at runtime in standalone executable") catch unreachable,
156160
clap.parseParam("--bytecode Use a bytecode cache") catch unreachable,
157161
clap.parseParam("--watch Automatically restart the process on file change") catch unreachable,
158162
clap.parseParam("--no-clear-screen Disable clearing the terminal screen on reload when --watch is enabled") catch unreachable,
@@ -1063,6 +1067,42 @@ pub fn parse(allocator: std.mem.Allocator, ctx: Command.Context, comptime cmd: C
10631067
}
10641068
}
10651069

1070+
// Handle --compile-autoload-tsconfig flags (default: false, tsconfig not loaded at runtime)
1071+
{
1072+
const has_positive = args.flag("--compile-autoload-tsconfig");
1073+
const has_negative = args.flag("--no-compile-autoload-tsconfig");
1074+
1075+
if (has_positive or has_negative) {
1076+
if (!ctx.bundler_options.compile) {
1077+
Output.errGeneric("--compile-autoload-tsconfig requires --compile", .{});
1078+
Global.crash();
1079+
}
1080+
if (has_positive and has_negative) {
1081+
Output.errGeneric("Cannot use both --compile-autoload-tsconfig and --no-compile-autoload-tsconfig", .{});
1082+
Global.crash();
1083+
}
1084+
ctx.bundler_options.compile_autoload_tsconfig = has_positive;
1085+
}
1086+
}
1087+
1088+
// Handle --compile-autoload-package-json flags (default: false, package.json not loaded at runtime)
1089+
{
1090+
const has_positive = args.flag("--compile-autoload-package-json");
1091+
const has_negative = args.flag("--no-compile-autoload-package-json");
1092+
1093+
if (has_positive or has_negative) {
1094+
if (!ctx.bundler_options.compile) {
1095+
Output.errGeneric("--compile-autoload-package-json requires --compile", .{});
1096+
Global.crash();
1097+
}
1098+
if (has_positive and has_negative) {
1099+
Output.errGeneric("Cannot use both --compile-autoload-package-json and --no-compile-autoload-package-json", .{});
1100+
Global.crash();
1101+
}
1102+
ctx.bundler_options.compile_autoload_package_json = has_positive;
1103+
}
1104+
}
1105+
10661106
if (args.flag("--windows-hide-console")) {
10671107
// --windows-hide-console technically doesnt depend on WinAPI, but since since --windows-icon
10681108
// does, all of these customization options have been gated to windows-only

src/cli/build_command.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,8 @@ pub const BuildCommand = struct {
443443
.{
444444
.disable_default_env_files = !ctx.bundler_options.compile_autoload_dotenv,
445445
.disable_autoload_bunfig = !ctx.bundler_options.compile_autoload_bunfig,
446+
.disable_autoload_tsconfig = !ctx.bundler_options.compile_autoload_tsconfig,
447+
.disable_autoload_package_json = !ctx.bundler_options.compile_autoload_package_json,
446448
},
447449
) catch |err| {
448450
Output.printErrorln("failed to create executable: {s}", .{@errorName(err)});

src/options.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,6 +1772,7 @@ pub const BundleOptions = struct {
17721772
polyfill_node_globals: bool = false,
17731773
transform_only: bool = false,
17741774
load_tsconfig_json: bool = true,
1775+
load_package_json: bool = true,
17751776

17761777
rewrite_jest_for_tests: bool = false,
17771778

src/resolver/resolver.zig

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4122,30 +4122,32 @@ pub const Resolver = struct {
41224122
}
41234123

41244124
// Record if this directory has a package.json file
4125-
if (entries.getComptimeQuery("package.json")) |lookup| {
4126-
const entry = lookup.entry;
4127-
if (entry.kind(rfs, r.store_fd) == .file) {
4128-
info.package_json = if (r.usePackageManager() and !info.hasNodeModules() and !info.isNodeModules())
4129-
r.parsePackageJSON(path, if (FeatureFlags.store_file_descriptors) fd else .invalid, package_id, true) catch null
4130-
else
4131-
r.parsePackageJSON(path, if (FeatureFlags.store_file_descriptors) fd else .invalid, null, false) catch null;
4132-
4133-
if (info.package_json) |pkg| {
4134-
if (pkg.browser_map.count() > 0) {
4135-
info.enclosing_browser_scope = result.index;
4136-
info.package_json_for_browser_field = pkg;
4137-
}
4125+
if (r.opts.load_package_json) {
4126+
if (entries.getComptimeQuery("package.json")) |lookup| {
4127+
const entry = lookup.entry;
4128+
if (entry.kind(rfs, r.store_fd) == .file) {
4129+
info.package_json = if (r.usePackageManager() and !info.hasNodeModules() and !info.isNodeModules())
4130+
r.parsePackageJSON(path, if (FeatureFlags.store_file_descriptors) fd else .invalid, package_id, true) catch null
4131+
else
4132+
r.parsePackageJSON(path, if (FeatureFlags.store_file_descriptors) fd else .invalid, null, false) catch null;
4133+
4134+
if (info.package_json) |pkg| {
4135+
if (pkg.browser_map.count() > 0) {
4136+
info.enclosing_browser_scope = result.index;
4137+
info.package_json_for_browser_field = pkg;
4138+
}
41384139

4139-
if (pkg.name.len > 0 or r.care_about_bin_folder)
4140-
info.enclosing_package_json = pkg;
4140+
if (pkg.name.len > 0 or r.care_about_bin_folder)
4141+
info.enclosing_package_json = pkg;
41414142

4142-
if (pkg.dependencies.map.count() > 0 or pkg.package_manager_package_id != Install.invalid_package_id)
4143-
info.package_json_for_dependencies = pkg;
4143+
if (pkg.dependencies.map.count() > 0 or pkg.package_manager_package_id != Install.invalid_package_id)
4144+
info.package_json_for_dependencies = pkg;
41444145

4145-
if (r.debug_logs) |*logs| {
4146-
logs.addNoteFmt("Resolved package.json in \"{s}\"", .{
4147-
path,
4148-
});
4146+
if (r.debug_logs) |*logs| {
4147+
logs.addNoteFmt("Resolved package.json in \"{s}\"", .{
4148+
path,
4149+
});
4150+
}
41494151
}
41504152
}
41514153
}

0 commit comments

Comments
 (0)