Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d3e954f
bake-decouple: fold CLI import.meta defines into one bake entry point
alii Jun 10, 2026
52b0d70
bake-decouple: project LinkerContext.framework to plain bool facts
alii Jun 10, 2026
c7a2bd8
bake-decouple: move serve dev-server option building into bake
alii Jun 10, 2026
910cdce
bake-decouple: move InternalBakeDev stmt transform into bake via hook
alii Jun 10, 2026
c86ee34
bake-decouple: collapse BuiltInModule conversion in resolver options …
alii Jun 10, 2026
09e0ee9
bake-decouple: use canonical BuiltInModule in ParseTask, drop stale n…
alii Jun 10, 2026
db969ef
bake-decouple: erase bake types from server_body plugin/router seams
alii Jun 10, 2026
f0acede
bake-decouple: move production pipeline into bake, extract bake_types…
alii Jun 10, 2026
b394c1a
bake-decouple: move Bun.serve dev-server glue from server/mod.rs into…
alii Jun 10, 2026
d2da829
bake-decouple: move Target::bake_graph mapping into the bake_types seam
alii Jun 10, 2026
1f2c482
bake-decouple: move dev server asset URL prefix to bun_options_types
alii Jun 10, 2026
2c34c4a
bake-decouple: type-erase dev-server options out of ServerConfig
alii Jun 10, 2026
ad0af03
bake-decouple: own Framework view in options; drop bake_types shim
alii Jun 10, 2026
ab91c7c
bake-decouple: project router storage types, mark remaining bake edges
alii Jun 10, 2026
711b11b
bake-decouple: supply manifest virtual-module names via BakeOptions
alii Jun 10, 2026
5b029b3
bake-decouple: type-erase the dev_server slot out of server/mod.rs
alii Jun 10, 2026
30b2f86
bake-decouple: rename BundlerOptions bake fields to CLI-flag names
alii Jun 10, 2026
0d6f9f7
bake-decouple: move AnyRequestContext dev-server views into bake
alii Jun 10, 2026
a855301
bake-decouple: make HTMLBundle dev_server_id an opaque host token
alii Jun 10, 2026
29272a3
bake-decouple: serve HMR runtime bytes to bundler via bake link hook
alii Jun 10, 2026
04570ff
bake-decouple: move bake feature-flag gates out of bun_core into bake
alii Jun 10, 2026
5e8bbbd
bake-decouple: project LinkerContext dev_server to a plain bool fact
alii Jun 10, 2026
249382f
bake-decouple: move serve 'app' option read+gating into bake hook
alii Jun 10, 2026
0ae91f7
bake-decouple: drop RequestContext's typed dev_server accessor
alii Jun 10, 2026
8602fd9
bake-decouple: move FrameworkFileSystemRouter class def into bake
alii Jun 10, 2026
3075b8a
bake-decouple: erase bake refs from server_body request/devtools paths
alii Jun 10, 2026
de6f23f
bake-decouple: make BundleV2 speak Target through the dev-server seam
alii Jun 10, 2026
6836bf2
bake-decouple: rename allow_bake_config to allow_dev_server_options
alii Jun 10, 2026
01dd6f4
bake-decouple: rustfmt fixups for fmt-violating sibling hunks
alii Jun 10, 2026
d9589a2
[autofix.ci] apply automated fixes
autofix-ci[bot] Jun 10, 2026
6562aa6
bake-decouple: per-block SAFETY comments on the slot vtable bodies
robobun Jun 10, 2026
ea15091
ci: retrigger
robobun Jun 11, 2026
c473c31
bake-decouple: fix stale bridge comment referencing config.bake
robobun Jun 11, 2026
a110d44
bake-decouple: carry thiserror refactor to the moved/new seam code
robobun Jul 12, 2026
4fcaa48
bake-decouple: re-open the bundler pipeline surface the extracted dri…
robobun Aug 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions src/bun_core/feature_flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,3 @@ pub fn is_libdeflate_enabled() -> bool {

!feature_flag::BUN_FEATURE_FLAG_NO_LIBDEFLATE.get()
}

/// Enable the "app" option in Bun.serve. This option will likely be removed
/// in favor of HTML loaders and configuring framework options in bunfig.toml
pub fn bake() -> bool {
// In canary or if an environment variable is specified.
env::IS_CANARY || env::IS_DEBUG || feature_flag::BUN_FEATURE_FLAG_EXPERIMENTAL_BAKE.get()
}

/// Additional debugging features for bake.DevServer, such as the incremental visualizer.
/// To use them, extra flags are passed in addition to this one.
pub const BAKE_DEBUGGING_FEATURES: bool = env::IS_CANARY || env::IS_DEBUG;
41 changes: 28 additions & 13 deletions src/bundler/LinkerContext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use bun_sourcemap::{
};
// Note: alias the *module* (not the `ThreadPool` struct) so
// `ThreadPoolLib::Task` / `ThreadPoolLib::Batch` resolve as nested items.
use crate::bake_types as bake;
use bun_ast::{ImportKind, ImportRecord};
use bun_threading::{WaitGroup, thread_pool as ThreadPoolLib};

Expand Down Expand Up @@ -67,12 +66,21 @@ pub use crate::linker_context::static_route_visitor as StaticRouteVisitor;
// `linker_context/doStep5.rs`), not free functions — no item re-export.
pub(crate) use crate::linker_context::compute_cross_chunk_dependencies::compute_cross_chunk_dependencies;
pub use crate::linker_context::do_step5;
pub(crate) use crate::linker_context::generate_chunks_in_parallel::generate_chunks_in_parallel;
pub use crate::linker_context::generate_chunks_in_parallel::generate_chunks_in_parallel;
pub(crate) use crate::linker_context::post_process_css_chunk::post_process_css_chunk;
pub(crate) use crate::linker_context::post_process_html_chunk::post_process_html_chunk;
pub(crate) use crate::linker_context::post_process_js_chunk::post_process_js_chunk;
pub(crate) use crate::linker_context::rename_symbols_in_chunk::rename_symbols_in_chunk;

/// Subset of the framework config that chunk generation consults, projected
/// by value when `BundleV2` is set up so the linker holds no backref into the
/// framework struct.
#[derive(Copy, Clone)]
pub struct FrameworkInfo {
pub has_server_components: bool,
pub is_built_in_react: bool,
}

pub struct LinkerContext<'a> {
pub(crate) parse_graph: *mut Graph<'a>,
pub graph: LinkerGraph<'a>,
Expand Down Expand Up @@ -119,17 +127,18 @@ pub struct LinkerContext<'a> {

pub(crate) has_any_css_locals: AtomicU32,

/// Used by Bake to extract []CompileResult before it is joined.
/// CYCLEBREAK GENUINE: erased bake::DevServer (see bundle_v2::dispatch).
pub dev_server: Option<crate::dispatch::DevServerHandle>,
pub(crate) framework: Option<bun_ptr::BackRef<bake::Framework>>,
/// True when a dev server is driving this bundle. Chunk generation only
/// branches on the fact; all dispatch goes through the erased handle on
/// `BundleV2.dev_server`, which is the single owner of that seam.
pub has_dev_server: bool,
pub framework: Option<FrameworkInfo>,

pub(crate) mangled_props: MangledProps,
}

// SAFETY: `LinkerContext` is shared across the worker pool via `each_ptr` /
// `SourceMapDataTask`. The raw-pointer fields (`parse_graph`, `resolver`,
// `r#loop`, `framework`) are backrefs into `BundleV2`/`Transpiler` whose
// `r#loop`) are backrefs into `BundleV2`/`Transpiler` whose
// lifetimes strictly outlive every parallel section, and per-thread writes go
// to disjoint SoA slots (see `compute_line_offsets`).
unsafe impl<'a> Send for LinkerContext<'a> {}
Expand All @@ -155,7 +164,7 @@ impl<'a> Default for LinkerContext<'a> {
source_maps: Default::default(),
pending_task_count: AtomicU32::new(0),
has_any_css_locals: AtomicU32::new(0),
dev_server: None,
has_dev_server: false,
framework: None,
mangled_props: Default::default(),
}
Expand Down Expand Up @@ -688,7 +697,7 @@ impl<'a> LinkerContext<'a> {
/// # Safety
/// `bundle` must be valid for the call and `self` must be `(*bundle).linker`.
#[inline(never)]
pub(crate) unsafe fn link(
pub unsafe fn link(
&mut self,
bundle: *mut BundleV2<'a>,
entry_points: &[Index],
Expand Down Expand Up @@ -2988,7 +2997,7 @@ impl<'a> LinkerContext<'a> {
}

/// `log` is an explicit parameter (not `self.log`) because the dev-server
/// caller (`finish_from_bake_dev_server`) runs this *before* `load()` has
/// caller (`finish_from_dev_server`) runs this *before* `load()` has
/// initialized `self.log`, passing a stack-local `Log` instead.
pub(crate) fn scan_css_imports(
file_source_index: u32,
Expand Down Expand Up @@ -4179,7 +4188,7 @@ impl PartialEq for MatchImport {
pub struct StmtList {
// Temporary scratch buffers: plain `Vec`s on the global allocator
// (cleared/reused per chunk, freed by Drop).
pub(crate) inside_wrapper_prefix: InsideWrapperPrefix,
pub inside_wrapper_prefix: InsideWrapperPrefix,
pub(crate) outside_wrapper_prefix: Vec<Stmt>,
pub(crate) inside_wrapper_suffix: Vec<Stmt>,
pub(crate) all_stmts: Vec<Stmt>,
Expand Down Expand Up @@ -4211,7 +4220,10 @@ impl InsideWrapperPrefix {
}

impl InsideWrapperPrefix {
pub(crate) fn append_non_dependency(&mut self, stmt: Stmt) -> Result<(), AllocError> {
// `pub`: also called by the `Format::InternalBakeDev` statement
// conversion in `bun_runtime`'s bake module (see
// `crate::convert_stmts_for_chunk_hmr`).
pub fn append_non_dependency(&mut self, stmt: Stmt) -> Result<(), AllocError> {
self.stmts.push(stmt);
Ok(())
}
Expand Down Expand Up @@ -4370,7 +4382,10 @@ impl StmtList {
}
}

pub(crate) fn append(&mut self, list: StmtListWhich, stmt: Stmt) {
// `pub`: also called by the `Format::InternalBakeDev` statement
// conversion in `bun_runtime`'s bake module (see
// `crate::convert_stmts_for_chunk_hmr`).
pub fn append(&mut self, list: StmtListWhich, stmt: Stmt) {
match list {
StmtListWhich::OutsideWrapperPrefix => self.outside_wrapper_prefix.push(stmt),
StmtListWhich::InsideWrapperSuffix => self.inside_wrapper_suffix.push(stmt),
Expand Down
15 changes: 8 additions & 7 deletions src/bundler/ParseTask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use bun_ast::{Loc, Location, Log, Msg, Source};
use bun_collections::VecExt;
use bun_core::strings;
use bun_core::{self, FeatureFlags, declare_scope, scoped_log};
use bun_options_types::BuiltInModule;
use bun_sys::Fd;
use bun_threading::thread_pool as ThreadPoolLib;

Expand Down Expand Up @@ -1310,7 +1311,7 @@ pub mod parse_worker {
write!(
&mut buf,
"{}/{}{}",
crate::bake_types::ASSET_PREFIX,
bun_options_types::DEV_SERVER_ASSET_PREFIX,
bun_core::fmt::bytes_to_hex_lower_string(&content_hash.to_ne_bytes()),
bstr::BStr::new(bun_paths::extension(source.path.text)),
)
Expand Down Expand Up @@ -1410,7 +1411,7 @@ pub mod parse_worker {
if let Some(f) = &ctx.framework {
if let Some(file) = f.built_in_modules.get(file_path.text) {
match file {
crate::bake_types::BuiltInModule::Code(code) => {
BuiltInModule::Code(code) => {
break 'brk Ok(CacheEntry {
contents: crate::cache::Contents::SharedBuffer {
ptr: code.as_ptr(),
Expand All @@ -1420,7 +1421,7 @@ pub mod parse_worker {
..Default::default()
});
}
crate::bake_types::BuiltInModule::Import(path) => {
BuiltInModule::Import(path) => {
*file_path = Fs::Path::init(path);
break 'lookup_builtin;
}
Expand Down Expand Up @@ -2543,10 +2544,10 @@ pub mod parse_worker {
bun_ast::runtime::ServerComponentsMode::None
};

// `transpiler.options.framework: Option<&bake_types::Framework>`
// vs `opts.framework: Option<&js_parser::options::Framework>` — both
// TYPE_ONLY mirrors of `bake.Framework`. Project the fields the parser
// reads into the parser-side mirror and bump-alloc
// `transpiler.options.framework` and `opts.framework` are distinct
// TYPE_ONLY mirrors of the runtime-side framework config (the bundler
// seam struct vs `js_parser::options::Framework`). Project the fields
// the parser reads into the parser-side mirror and bump-alloc
// so `opts` can borrow it.
opts.framework = topts.framework.map(|f| {
// `Framework` is bump-allocated below, so `Drop` never runs — use arena-owned slices.
Expand Down
97 changes: 97 additions & 0 deletions src/bundler/bake_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//! CYCLEBREAK(b0) TYPE_ONLY seam module: pure value types shared between the
//! bundler internals and `bun_runtime::bake`, kept at the lower tier so the
//! bundler can consume them without depending on the full DevServer.
//! `bun_runtime::bake` re-exports these as the canonical defs and constructs
//! values of them (e.g. `Framework` is projected from the runtime-side
//! superset via `as_bundler_view`).

#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, core::marker::ConstParamTy)]
pub enum Side {
Client = 0,
Server = 1,
}
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Graph {
Client = 0,
Server = 1,
Ssr = 2,
}
/// Used for the per-file `// path (target)` comment
/// in postProcessJSChunk and friends.
impl From<Graph> for &'static str {
fn from(g: Graph) -> Self {
match g {
Graph::Client => "client",
Graph::Server => "server",
Graph::Ssr => "ssr",
}
}
}
impl Side {
pub fn graph(self) -> Graph {
match self {
Side::Client => Graph::Client,
Side::Server => Graph::Server,
}
}
}
/// Bundler-only `Target` extension: which dev-server graph a file bundled for
/// that target lands in. Declared next to `Graph` because the canonical
/// `Target` lives in `bun_ast` (lower tier, cannot name seam types); callers
/// import it from here (`crate::bake_types::TargetExt`).
pub trait TargetExt: Copy {
fn bake_graph(self) -> Graph;
}
impl TargetExt for bun_ast::Target {
Comment thread
robobun marked this conversation as resolved.
fn bake_graph(self) -> Graph {
use bun_ast::Target;
match self {
Target::Browser => Graph::Client,
Target::ServerComponentsSsr => Graph::Ssr,
Target::BunMacro | Target::Bun | Target::Node => Graph::Server,
}
}
}
/// Canonical definition lives in `bun_options_types` (T3); re-exported
/// here so bundler and bake (in runtime, T6) share one nominal type.
pub use bun_options_types::BuiltInModule;

/// Bundler-owned TYPE_ONLY `Framework` view — canonical defs live in
/// `options_impl` (they are made of bundler/parser vocabulary, no bake
/// references); re-exported here so `bun_runtime::bake` keeps reaching them
/// through the seam module when projecting its canonical `bake.Framework`
/// via `as_bundler_view`.
pub use crate::options_impl::{Framework, ReactFastRefresh, ServerComponents};

/// Seam type: the HMR runtime preamble the linker splices ahead of each
/// `Format::InternalBakeDev` chunk.
#[derive(Clone, Copy)]
pub struct HmrRuntime {
pub code: &'static [u8],
}
/// Alias used at the crate root (`crate::HmrRuntimeSide`); identical to `Side`.
pub(crate) type HmrRuntimeSide = Side;

/// The runtime's bytes are embedded once, by `bun_runtime`'s dev-server module
/// (which also hands them to JSC); the bundler reaches them through the
/// link-time hook below, same pattern as `__bun_bake_convert_stmts_for_chunk_hmr`
/// in `lib.rs`. Memoized per side.
pub(crate) fn get_hmr_runtime(side: Side) -> HmrRuntime {
static CLIENT: std::sync::OnceLock<HmrRuntime> = std::sync::OnceLock::new();
static SERVER: std::sync::OnceLock<HmrRuntime> = std::sync::OnceLock::new();
let cell = match side {
Side::Client => &CLIENT,
Side::Server => &SERVER,
};
*cell.get_or_init(|| __bun_bake_get_hmr_runtime(side))
}

unsafe extern "Rust" {
/// Defined `#[no_mangle]` in `bun_runtime` (`bake/bake_body.rs`). All
/// argument/return types are safe Rust values (no raw-pointer
/// preconditions), so the link-time-resolved body upholds Rust's
/// invariants on its own.
safe fn __bun_bake_get_hmr_runtime(side: Side) -> HmrRuntime;
}
Loading