From e9226c9bec812c37e32f8f2ef307f8a7fbf99aa7 Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Sun, 2 Aug 2026 07:29:02 +0000 Subject: [PATCH 1/5] bundler(options): collapse bool pairs into OfflineMode/CompileMode enums Two related type-hardening refactors with no behavior change: install_preference: OfflineMode Replaces the prefer_offline_install + prefer_latest_install bool pair on the bundler and resolver BundleOptions. Every write site already decoded these from an OfflineMode and prefer_latest_install was write-only dead state. The one read site (resolver disk-cache lookup) now checks the enum directly. compile_mode: CompileMode Replaces the compile + compile_to_standalone_html bool pair on the bundler BundleOptions and LinkerOptions. The two were mutually exclusive by construction (both build_command and Bun.build clear compile when setting compile_to_standalone_html) so a three-state enum makes the invariant unrepresentable-if-wrong. The resolver projection keeps its compile: bool and is fed compile_mode.is_executable(). Net -1 line across 18 files; three write sites each drop ~10 lines of duplicated enum-to-bool decoding plus the comments explaining why the resolver lacks prefer_latest_install. --- src/bundler/HTMLImportManifest.rs | 2 +- src/bundler/LinkerContext.rs | 6 +-- src/bundler/ParseTask.rs | 6 +-- src/bundler/bundle_v2.rs | 8 ++-- .../linker_context/OutputFileListBuilder.rs | 4 +- .../generateChunksInParallel.rs | 12 +++--- .../generateCompileResultForHtmlChunk.rs | 2 +- .../linker_context/postProcessJSChunk.rs | 2 +- src/bundler/options.rs | 41 +++++++++++++------ src/bundler/transpiler.rs | 4 +- src/options_types/offline_mode.rs | 3 +- src/resolver/options.rs | 4 +- src/resolver/resolver.rs | 2 +- src/runtime/api/js_bundle_completion_task.rs | 14 ++++--- src/runtime/bake/production.rs | 18 ++------ src/runtime/cli/build_command.rs | 9 ++-- src/runtime/cli/repl_command.rs | 17 ++------ src/runtime/cli/run_command.rs | 7 +--- 18 files changed, 80 insertions(+), 81 deletions(-) diff --git a/src/bundler/HTMLImportManifest.rs b/src/bundler/HTMLImportManifest.rs index 5d3a551cbcc0..3b8e54eed82d 100644 --- a/src/bundler/HTMLImportManifest.rs +++ b/src/bundler/HTMLImportManifest.rs @@ -193,7 +193,7 @@ pub(crate) fn write( writer.write_all(b"{")?; - let inject_compiler_filesystem_prefix = options.compile; + let inject_compiler_filesystem_prefix = options.compile_mode.is_executable(); // Use the server-side public path here. let public_path: &[u8] = &options.public_path; let mut temp_buffer: Vec = Vec::new(); diff --git a/src/bundler/LinkerContext.rs b/src/bundler/LinkerContext.rs index 99d5286eef3a..98ddfb045167 100644 --- a/src/bundler/LinkerContext.rs +++ b/src/bundler/LinkerContext.rs @@ -1239,10 +1239,9 @@ pub struct LinkerOptions { pub(crate) banner: &'static [u8], pub(crate) footer: &'static [u8], pub(crate) css_chunking: bool, - pub(crate) compile_to_standalone_html: bool, pub(crate) source_maps: SourceMapOption, pub(crate) target: Target, - pub(crate) compile: bool, + pub(crate) compile_mode: crate::options::CompileMode, pub(crate) metafile: bool, /// Path to write JSON metafile (for Bun.build API) pub(crate) metafile_json_path: &'static [u8], @@ -1268,10 +1267,9 @@ impl Default for LinkerOptions { banner: b"", footer: b"", css_chunking: false, - compile_to_standalone_html: false, source_maps: SourceMapOption::None, target: Target::Browser, - compile: false, + compile_mode: crate::options::CompileMode::None, metafile: false, metafile_json_path: b"", metafile_markdown_path: b"", diff --git a/src/bundler/ParseTask.rs b/src/bundler/ParseTask.rs index e0ccd7659e32..9d220dd6766f 100644 --- a/src/bundler/ParseTask.rs +++ b/src/bundler/ParseTask.rs @@ -858,7 +858,7 @@ pub mod parse_worker { source, Some(b"text/plain"), None, - topts.compile_to_standalone_html, + topts.compile_mode.is_standalone_html(), ); return Ok(ast); } @@ -899,7 +899,7 @@ pub mod parse_worker { source, Some(b"text/html"), None, - topts.compile_to_standalone_html, + topts.compile_mode.is_standalone_html(), ); return Ok(ast); } @@ -1318,7 +1318,7 @@ pub mod parse_worker { source, None, Some(unique_key), - topts.compile_to_standalone_html, + topts.compile_mode.is_standalone_html(), ); return Ok(ast); } diff --git a/src/bundler/bundle_v2.rs b/src/bundler/bundle_v2.rs index 648bb40bcf38..3f64795e6d12 100644 --- a/src/bundler/bundle_v2.rs +++ b/src/bundler/bundle_v2.rs @@ -1542,7 +1542,7 @@ pub mod bv2_impl { unsafe { bun_ptr::detach_lifetime_ref::(self.arena()) }; let this_transpiler: &Transpiler<'a> = &*self.transpiler; - let this_compile = this_transpiler.options.compile; + let this_compile = this_transpiler.options.compile_mode.is_executable(); let this_env = this_transpiler.env; // SAFETY: `self.transpiler` (and the data its `&'a` fields borrow) @@ -2800,8 +2800,6 @@ pub mod bv2_impl { // SAFETY: same `'a`-owned `Transpiler` field as `banner` above. this.linker.options.footer = unsafe { interned_slice(&this.transpiler.options.footer) }; this.linker.options.css_chunking = this.transpiler.options.css_chunking; - this.linker.options.compile_to_standalone_html = - this.transpiler.options.compile_to_standalone_html; this.linker.options.source_maps = this.transpiler.options.source_map; this.linker.options.tree_shaking = this.transpiler.options.tree_shaking; // SAFETY: same `'a`-owned `Transpiler` field as `banner` above. @@ -2810,7 +2808,7 @@ pub mod bv2_impl { this.linker.options.target = this.transpiler.options.target; this.linker.options.output_format = this.transpiler.options.output_format; this.linker.options.generate_bytecode_cache = this.transpiler.options.bytecode; - this.linker.options.compile = this.transpiler.options.compile; + this.linker.options.compile_mode = this.transpiler.options.compile_mode; this.linker.options.metafile = this.transpiler.options.metafile; // SAFETY: same `'a`-owned `Transpiler` field as `banner` above. this.linker.options.metafile_json_path = @@ -4127,7 +4125,7 @@ pub mod bv2_impl { } let mut v = Vec::new(); template - .print(&mut v, !self.transpiler.options.compile) + .print(&mut v, !self.transpiler.options.compile_mode.is_executable()) .expect("oom"); v.into_boxed_slice() }; diff --git a/src/bundler/linker_context/OutputFileListBuilder.rs b/src/bundler/linker_context/OutputFileListBuilder.rs index 92e4c197047e..7633fb5f8319 100644 --- a/src/bundler/linker_context/OutputFileListBuilder.rs +++ b/src/bundler/linker_context/OutputFileListBuilder.rs @@ -129,14 +129,14 @@ impl OutputFileList { // module_info is generated for ESM bytecode in --compile builds let module_info_count: usize = if c.options.generate_bytecode_cache && c.options.output_format == Format::Esm - && c.options.compile + && c.options.compile_mode.is_executable() { bytecode_count } else { 0 }; - let additional_output_files_count: usize = if c.options.compile_to_standalone_html { + let additional_output_files_count: usize = if c.options.compile_mode.is_standalone_html() { 0 } else { parse_graph.additional_output_files.len() diff --git a/src/bundler/linker_context/generateChunksInParallel.rs b/src/bundler/linker_context/generateChunksInParallel.rs index 6d44301fcbe1..77a2a7c61c8a 100644 --- a/src/bundler/linker_context/generateChunksInParallel.rs +++ b/src/bundler/linker_context/generateChunksInParallel.rs @@ -344,7 +344,7 @@ pub(crate) fn generate_chunks_in_parallel( // runtime bunfs references to out-of-root entrypoints resolve. chunk .template - .print(&mut rel_path, !c.options.compile) + .print(&mut rel_path, !c.options.compile_mode.is_executable()) .expect("write to Vec"); path::resolve_path::platform_to_posix_in_place::(&mut rel_path); @@ -451,7 +451,7 @@ pub(crate) fn generate_chunks_in_parallel( // those placeholders with the resolved paths and serialize. if c.options.generate_bytecode_cache && c.options.output_format == options::Format::Esm - && c.options.compile + && c.options.compile_mode.is_executable() { // Build map from unique_key -> final resolved path // SAFETY: c points to LinkerContext which is the `linker` field of BundleV2. @@ -551,7 +551,7 @@ pub(crate) fn generate_chunks_in_parallel( // disjoint from anything `c` mutates. let resolver = c.resolver.expect("resolver set in load()"); let root_path: &[u8] = &resolver.opts.output_dir; - let is_standalone = c.options.compile_to_standalone_html; + let is_standalone = c.options.compile_mode.is_standalone_html(); let more_than_one_output = !is_standalone && (c.parse_graph().additional_output_files.len() > 0 || c.options.generate_bytecode_cache @@ -734,7 +734,7 @@ pub(crate) fn generate_chunks_in_parallel( } // Don't write to disk if compile mode is enabled - we need buffer values for compilation - let is_compile = bundler.transpiler.options.compile; + let is_compile = bundler.transpiler.options.compile_mode.is_executable(); if root_path.len() > 0 && !is_compile { write_output_files_to_disk( c, @@ -1010,7 +1010,7 @@ pub(crate) fn generate_chunks_in_parallel( // from server builds, and normalize with cheapPrefixNormalizer for consistency // with module_info path fixup. // For non-compile builds, use the normal .jsc extension. - let source_provider_url = if c.options.compile { + let source_provider_url = if c.options.compile_mode.is_executable() { let normalizer = cheap_prefix_normalizer(public_path, &chunk.final_rel_path); BunString::create_format(format_args!( @@ -1101,7 +1101,7 @@ pub(crate) fn generate_chunks_in_parallel( let module_info_output_file: Option = 'brk: { if c.options.generate_bytecode_cache && c.options.output_format == options::Format::Esm - && c.options.compile + && c.options.compile_mode.is_executable() { let loader: Loader = if chunk.entry_point.is_entry_point() { c.parse_graph().input_files.items_loader() diff --git a/src/bundler/linker_context/generateCompileResultForHtmlChunk.rs b/src/bundler/linker_context/generateCompileResultForHtmlChunk.rs index 3d46e8fe45af..833b5d3dc30c 100644 --- a/src/bundler/linker_context/generateCompileResultForHtmlChunk.rs +++ b/src/bundler/linker_context/generateCompileResultForHtmlChunk.rs @@ -386,7 +386,7 @@ fn generate_compile_result_for_html_chunk_impl<'a>( // pointer today. let log: *mut Log = c.log; let minify_whitespace = c.options.minify_whitespace; - let compile_to_standalone_html = c.options.compile_to_standalone_html; + let compile_to_standalone_html = c.options.compile_mode.is_standalone_html(); let has_dev_server = c.dev_server.is_some(); let contents: &[u8] = &sources[source_index as usize].contents; let records = import_records[source_index as usize].as_slice(); diff --git a/src/bundler/linker_context/postProcessJSChunk.rs b/src/bundler/linker_context/postProcessJSChunk.rs index 7a73067f3afb..3b61d91abd60 100644 --- a/src/bundler/linker_context/postProcessJSChunk.rs +++ b/src/bundler/linker_context/postProcessJSChunk.rs @@ -98,7 +98,7 @@ pub(crate) fn post_process_js_chunk( // Create ModuleInfo for ESM bytecode in --compile builds let generate_module_info = c.options.generate_bytecode_cache && c.options.output_format == options::OutputFormat::Esm - && c.options.compile; + && c.options.compile_mode.is_executable(); let loader = c.parse_graph().input_files.items_loader()[chunk.entry_point.source_index() as usize]; let is_typescript = loader.is_type_script(); diff --git a/src/bundler/options.rs b/src/bundler/options.rs index 0470a8e38238..879e06641883 100644 --- a/src/bundler/options.rs +++ b/src/bundler/options.rs @@ -21,6 +21,7 @@ pub use defines::Define; // traits into scope so the associated-fn call syntax below resolves. use crate::defines::{DefineDataExt as _, DefineExt as _}; pub use bun_options_types::global_cache::GlobalCache; +pub use bun_options_types::offline_mode::OfflineMode; // Canonical alias lives in the resolver. pub use bun_resolver::package_json::ConditionsMap; @@ -1082,6 +1083,28 @@ pub enum SourceMapOption { Linked, } +/// What `--compile` resolved to for this bundle: a native executable, +/// a self-contained HTML file, or neither. Executable and StandaloneHtml +/// are mutually exclusive. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum CompileMode { + #[default] + None, + Executable, + StandaloneHtml, +} + +impl CompileMode { + #[inline] + pub const fn is_executable(self) -> bool { + matches!(self, CompileMode::Executable) + } + #[inline] + pub const fn is_standalone_html(self) -> bool { + matches!(self, CompileMode::StandaloneHtml) + } +} + impl SourceMapOption { pub fn from_api(source_map: Option) -> SourceMapOption { match source_map.unwrap_or(api::SourceMapMode::None) { @@ -1242,8 +1265,7 @@ pub struct BundleOptions<'a> { pub disable_transpilation: bool, pub global_cache: GlobalCache, - pub prefer_offline_install: bool, - pub prefer_latest_install: bool, + pub install_preference: OfflineMode, /// Stored as a raw /// `NonNull` (not `Option<&'a _>`) because every CLI caller borrows the /// process-lifetime `ctx.install: Box` whose lifetime is @@ -1273,8 +1295,7 @@ pub struct BundleOptions<'a> { pub code_coverage: bool, pub debugger: bool, - pub compile: bool, - pub compile_to_standalone_html: bool, + pub compile_mode: CompileMode, pub metafile: bool, /// Path to write JSON metafile (for Bun.build API) pub metafile_json_path: Box<[u8]>, @@ -1446,8 +1467,7 @@ impl<'a> BundleOptions<'a> { packages: self.packages, disable_transpilation: self.disable_transpilation, global_cache: self.global_cache, - prefer_offline_install: self.prefer_offline_install, - prefer_latest_install: self.prefer_latest_install, + install_preference: self.install_preference, install: self.install, inlining: self.inlining, inline_entrypoint_import_meta_main: self.inline_entrypoint_import_meta_main, @@ -1463,8 +1483,7 @@ impl<'a> BundleOptions<'a> { bytecode: self.bytecode, code_coverage: self.code_coverage, debugger: self.debugger, - compile: self.compile, - compile_to_standalone_html: self.compile_to_standalone_html, + compile_mode: self.compile_mode, metafile: self.metafile, metafile_json_path: self.metafile_json_path.clone(), metafile_markdown_path: self.metafile_markdown_path.clone(), @@ -1700,8 +1719,7 @@ impl<'a> BundleOptions<'a> { packages: PackagesOption::Bundle, disable_transpilation: false, global_cache: GlobalCache::disable, - prefer_offline_install: false, - prefer_latest_install: false, + install_preference: OfflineMode::Online, install: None, inlining: false, inline_entrypoint_import_meta_main: false, @@ -1716,8 +1734,7 @@ impl<'a> BundleOptions<'a> { bytecode: false, code_coverage: false, debugger: false, - compile: false, - compile_to_standalone_html: false, + compile_mode: CompileMode::None, metafile: false, metafile_json_path: Box::default(), metafile_markdown_path: Box::default(), diff --git a/src/bundler/transpiler.rs b/src/bundler/transpiler.rs index cd24d1c280bc..4064d0b3cd4a 100644 --- a/src/bundler/transpiler.rs +++ b/src/bundler/transpiler.rs @@ -1116,7 +1116,7 @@ fn resolver_bundle_options_subset( main_fields_is_default: src.transform_options.main_fields.is_empty(), mark_builtins_as_external: src.mark_builtins_as_external, polyfill_node_globals: src.polyfill_node_globals, - prefer_offline_install: src.prefer_offline_install, + install_preference: src.install_preference, preserve_symlinks: src.preserve_symlinks, rewrite_jest_for_tests: src.rewrite_jest_for_tests, tsconfig_override: src.tsconfig_override.clone(), @@ -1128,7 +1128,7 @@ fn resolver_bundle_options_subset( output_dir: src.output_dir.clone(), root_dir: src.root_dir.clone(), public_path: src.public_path.clone(), - compile: src.compile, + compile: src.compile_mode.is_executable(), supports_multiple_outputs: src.supports_multiple_outputs, tree_shaking: src.tree_shaking, allow_runtime: src.allow_runtime, diff --git a/src/options_types/offline_mode.rs b/src/options_types/offline_mode.rs index 0833ca1e1ada..2ad7fdbb4992 100644 --- a/src/options_types/offline_mode.rs +++ b/src/options_types/offline_mode.rs @@ -1,6 +1,7 @@ #[repr(u8)] -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] pub enum OfflineMode { + #[default] Online, Latest, Offline, diff --git a/src/resolver/options.rs b/src/resolver/options.rs index a8815289577b..6000dfd81eb7 100644 --- a/src/resolver/options.rs +++ b/src/resolver/options.rs @@ -230,7 +230,7 @@ pub struct BundleOptions { pub main_fields_is_default: bool, pub mark_builtins_as_external: bool, pub polyfill_node_globals: bool, - pub prefer_offline_install: bool, + pub install_preference: bun_options_types::offline_mode::OfflineMode, pub preserve_symlinks: bool, pub rewrite_jest_for_tests: bool, pub tsconfig_override: Option>, @@ -273,7 +273,7 @@ impl Default for BundleOptions { main_fields_is_default: true, mark_builtins_as_external: false, polyfill_node_globals: false, - prefer_offline_install: false, + install_preference: Default::default(), preserve_symlinks: false, rewrite_jest_for_tests: false, tsconfig_override: None, diff --git a/src/resolver/resolver.rs b/src/resolver/resolver.rs index b3c577215aee..a728d278a21b 100644 --- a/src/resolver/resolver.rs +++ b/src/resolver/resolver.rs @@ -3586,7 +3586,7 @@ impl<'a> Resolver<'a> { } } - if self.opts.prefer_offline_install { + if self.opts.install_preference == bun_options_types::offline_mode::OfflineMode::Offline { if let Some(package_id) = pm!().resolve_from_disk_cache(esm.name, &version) { *input_package_id_ = package_id; return DependencyToResolve::Resolution( diff --git a/src/runtime/api/js_bundle_completion_task.rs b/src/runtime/api/js_bundle_completion_task.rs index 7cc41879aaef..063ea3a45582 100644 --- a/src/runtime/api/js_bundle_completion_task.rs +++ b/src/runtime/api/js_bundle_completion_task.rs @@ -884,7 +884,11 @@ impl CompletionStruct for JSBundleCompletionTask { transpiler.options.output_format = config.format; transpiler.options.bytecode = config.bytecode; - transpiler.options.compile = config.compile.is_some(); + transpiler.options.compile_mode = if config.compile.is_some() { + options::CompileMode::Executable + } else { + options::CompileMode::None + }; // For compile mode, set the public_path to the target-specific base path // This ensures embedded resources like yoga.wasm are correctly found @@ -919,7 +923,7 @@ impl CompletionStruct for JSBundleCompletionTask { transpiler.options.ignore_dce_annotations = config.ignore_dce_annotations; transpiler.options.tree_shaking_override = config.tree_shaking; transpiler.options.css_chunking = config.css_chunking; - transpiler.options.compile_to_standalone_html = 'brk: { + let compile_to_standalone_html = 'brk: { if config.compile.is_none() || config.target != bun_ast::Target::Browser { break 'brk false; } @@ -932,8 +936,8 @@ impl CompletionStruct for JSBundleCompletionTask { config.entry_points.count() > 0 }; // When compiling to standalone HTML, don't use the bun executable compile path - if transpiler.options.compile_to_standalone_html { - transpiler.options.compile = false; + if compile_to_standalone_html { + transpiler.options.compile_mode = options::CompileMode::StandaloneHtml; config.compile = None; } // `BundleOptions.{banner,footer}` are `Cow<'static, [u8]>`; clone into @@ -966,7 +970,7 @@ impl CompletionStruct for JSBundleCompletionTask { Some(unsafe { &*core::ptr::from_ref(&config.optimize_imports) }); } - if transpiler.options.compile { + if transpiler.options.compile_mode.is_executable() { // Emitting DCE annotations is nonsensical in --compile. transpiler.options.emit_dce_annotations = false; } diff --git a/src/runtime/bake/production.rs b/src/runtime/bake/production.rs index 137be91eb6e6..ad420401ee50 100644 --- a/src/runtime/bake/production.rs +++ b/src/runtime/bake/production.rs @@ -140,23 +140,13 @@ pub fn build_command(ctx: Context) -> crate::Result<()> { b.options.install = install_ptr; b.resolver.opts.install = install_ptr; b.resolver.opts.global_cache = ctx.debug.global_cache; - b.resolver.opts.prefer_offline_install = ctx + let offline = ctx .debug .offline_mode_setting - .unwrap_or(OfflineMode::Online) - == OfflineMode::Offline; - // Note: `bun_resolver::options::BundleOptions` has no - // `prefer_latest_install` field; compute the value once - // and assign only to `b.options` (which does carry it). The resolver - // never reads it. - let prefer_latest = ctx - .debug - .offline_mode_setting - .unwrap_or(OfflineMode::Online) - == OfflineMode::Latest; + .unwrap_or(OfflineMode::Online); + b.resolver.opts.install_preference = offline; b.options.global_cache = b.resolver.opts.global_cache; - b.options.prefer_offline_install = b.resolver.opts.prefer_offline_install; - b.options.prefer_latest_install = prefer_latest; + b.options.install_preference = offline; // SAFETY: `b.env` is the Transpiler-owned `*mut Loader`; store it // as `NonNull` (not `&Loader`) because `configure_defines()` below // reborrows the same allocation as `&mut Loader` via `run_env_loader()`, diff --git a/src/runtime/cli/build_command.rs b/src/runtime/cli/build_command.rs index c687f938fe97..92003b6f7c64 100644 --- a/src/runtime/cli/build_command.rs +++ b/src/runtime/cli/build_command.rs @@ -154,7 +154,11 @@ impl BuildCommand { this_transpiler.options.source_map = options::SourceMapOption::from_api(ctx.args.source_map); - this_transpiler.options.compile = ctx.bundler_options.compile; + this_transpiler.options.compile_mode = if ctx.bundler_options.compile { + options::CompileMode::Executable + } else { + options::CompileMode::None + }; if this_transpiler.options.source_map == options::SourceMapOption::External && ctx.bundler_options.outdir.is_empty() @@ -284,9 +288,8 @@ impl BuildCommand { Global::exit(1); } - this_transpiler.options.compile_to_standalone_html = true; // This is not a bun executable compile - clear compile flags - this_transpiler.options.compile = false; + this_transpiler.options.compile_mode = options::CompileMode::StandaloneHtml; ctx.bundler_options.compile = false; if ctx.bundler_options.outdir.is_empty() && outfile.is_empty() { diff --git a/src/runtime/cli/repl_command.rs b/src/runtime/cli/repl_command.rs index ca5f0f1c7224..061ac4de2b1a 100644 --- a/src/runtime/cli/repl_command.rs +++ b/src/runtime/cli/repl_command.rs @@ -104,22 +104,13 @@ impl ReplCommand { b.options.install = install_ptr; b.resolver.opts.install = install_ptr; b.resolver.opts.global_cache = ctx.debug.global_cache; - b.resolver.opts.prefer_offline_install = ctx + let offline = ctx .debug .offline_mode_setting - .unwrap_or(OfflineMode::Online) - == OfflineMode::Offline; - let prefer_latest = ctx - .debug - .offline_mode_setting - .unwrap_or(OfflineMode::Online) - == OfflineMode::Latest; - // The resolver's `BundleOptions` stub has no `prefer_latest_install` field and the - // resolver never reads it; only the bundler-side mirror carries it (matches - // run_command.rs / production.rs). + .unwrap_or(OfflineMode::Online); + b.resolver.opts.install_preference = offline; b.options.global_cache = b.resolver.opts.global_cache; - b.options.prefer_offline_install = b.resolver.opts.prefer_offline_install; - b.options.prefer_latest_install = prefer_latest; + b.options.install_preference = offline; b.resolver.env_loader = NonNull::new(b.env); b.options.env.behavior = EnvBehavior::LoadAllWithoutInlining; b.options.dead_code_elimination = false; // REPL needs all code diff --git a/src/runtime/cli/run_command.rs b/src/runtime/cli/run_command.rs index 2f58e6f9fdbf..fb001d360ae8 100644 --- a/src/runtime/cli/run_command.rs +++ b/src/runtime/cli/run_command.rs @@ -787,12 +787,9 @@ Full documentation is available at https://bun.com/docs/cli/run .debug .offline_mode_setting .unwrap_or(OfflineMode::Online); - b.resolver.opts.prefer_offline_install = offline == OfflineMode::Offline; - // resolver's forward-decl `BundleOptions` lacks - // `prefer_latest_install`; only the bundler-side mirror carries it. + b.resolver.opts.install_preference = offline; b.options.global_cache = ctx.debug.global_cache; - b.options.prefer_offline_install = offline == OfflineMode::Offline; - b.options.prefer_latest_install = offline == OfflineMode::Latest; + b.options.install_preference = offline; b.resolver.env_loader = ::core::ptr::NonNull::new(b.env); b.options.minify_identifiers = ctx.bundler_options.minify_identifiers; From 60163f616078bff6da26336a2810917ee0823950 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 2 Aug 2026 07:31:37 +0000 Subject: [PATCH 2/5] [autofix.ci] apply automated fixes --- src/bundler/bundle_v2.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bundler/bundle_v2.rs b/src/bundler/bundle_v2.rs index 3f64795e6d12..865665a9e986 100644 --- a/src/bundler/bundle_v2.rs +++ b/src/bundler/bundle_v2.rs @@ -4125,7 +4125,10 @@ pub mod bv2_impl { } let mut v = Vec::new(); template - .print(&mut v, !self.transpiler.options.compile_mode.is_executable()) + .print( + &mut v, + !self.transpiler.options.compile_mode.is_executable(), + ) .expect("oom"); v.into_boxed_slice() }; From 7151926396260610a95c67f3615a2706cafdbca0 Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Sun, 2 Aug 2026 07:32:37 +0000 Subject: [PATCH 3/5] trim CompileMode doc comment --- src/bundler/options.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/bundler/options.rs b/src/bundler/options.rs index 879e06641883..f47f206bd582 100644 --- a/src/bundler/options.rs +++ b/src/bundler/options.rs @@ -1083,9 +1083,7 @@ pub enum SourceMapOption { Linked, } -/// What `--compile` resolved to for this bundle: a native executable, -/// a self-contained HTML file, or neither. Executable and StandaloneHtml -/// are mutually exclusive. +/// What `--compile` resolved to for this bundle. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum CompileMode { #[default] From 9d0ff358d400dd46a83f677060b4fefbbefdbcad Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Sun, 2 Aug 2026 07:48:24 +0000 Subject: [PATCH 4/5] move CompileMode after SOURCE_MAP_OPTION_MAP to keep SourceMapOption adjacent to its impl --- src/bundler/options.rs | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/bundler/options.rs b/src/bundler/options.rs index f47f206bd582..19d50e403ecb 100644 --- a/src/bundler/options.rs +++ b/src/bundler/options.rs @@ -1083,26 +1083,6 @@ pub enum SourceMapOption { Linked, } -/// What `--compile` resolved to for this bundle. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub enum CompileMode { - #[default] - None, - Executable, - StandaloneHtml, -} - -impl CompileMode { - #[inline] - pub const fn is_executable(self) -> bool { - matches!(self, CompileMode::Executable) - } - #[inline] - pub const fn is_standalone_html(self) -> bool { - matches!(self, CompileMode::StandaloneHtml) - } -} - impl SourceMapOption { pub fn from_api(source_map: Option) -> SourceMapOption { match source_map.unwrap_or(api::SourceMapMode::None) { @@ -1137,6 +1117,26 @@ bun_core::comptime_string_map! { }; } +/// What `--compile` resolved to for this bundle. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum CompileMode { + #[default] + None, + Executable, + StandaloneHtml, +} + +impl CompileMode { + #[inline] + pub const fn is_executable(self) -> bool { + matches!(self, CompileMode::Executable) + } + #[inline] + pub const fn is_standalone_html(self) -> bool { + matches!(self, CompileMode::StandaloneHtml) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PackagesOption { Bundle, From eb6548e3c0a2b977582755ccd41cf4f34ba5ea3c Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Sun, 2 Aug 2026 08:12:00 +0000 Subject: [PATCH 5/5] import CompileMode in LinkerContext to match file convention --- src/bundler/LinkerContext.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bundler/LinkerContext.rs b/src/bundler/LinkerContext.rs index 98ddfb045167..d61282e6692e 100644 --- a/src/bundler/LinkerContext.rs +++ b/src/bundler/LinkerContext.rs @@ -34,7 +34,7 @@ use bun_ast::SideEffects; use bun_resolver::Resolver; use crate::Graph::Graph; -use crate::options::{Format, Loader, SourceMapOption, Target}; +use crate::options::{CompileMode, Format, Loader, SourceMapOption, Target}; use crate::{ AdditionalFile, BundleV2, Chunk, CompileResultForSourceMap, ContentHasher, ImportTracker, LinkerGraph, MangledProps, PartRange, StableRef, WrapKind, @@ -1241,7 +1241,7 @@ pub struct LinkerOptions { pub(crate) css_chunking: bool, pub(crate) source_maps: SourceMapOption, pub(crate) target: Target, - pub(crate) compile_mode: crate::options::CompileMode, + pub(crate) compile_mode: CompileMode, pub(crate) metafile: bool, /// Path to write JSON metafile (for Bun.build API) pub(crate) metafile_json_path: &'static [u8], @@ -1269,7 +1269,7 @@ impl Default for LinkerOptions { css_chunking: false, source_maps: SourceMapOption::None, target: Target::Browser, - compile_mode: crate::options::CompileMode::None, + compile_mode: CompileMode::None, metafile: false, metafile_json_path: b"", metafile_markdown_path: b"",