Skip to content
4 changes: 2 additions & 2 deletions src/ast/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ impl Index {
self.0
}

/// if you are within the parser, use p.isSourceRuntime() instead, as the
/// runtime index (0) is used as the id for single-file transforms.
/// The main `bun:runtime` module. In the parser use `p.is_source_runtime()`,
/// in the linker `LinkerGraph::is_runtime` (there can be a second runtime).
Comment thread
robobun marked this conversation as resolved.
Resolved
#[inline]
pub const fn is_runtime(self) -> bool {
self.0 == Self::RUNTIME.0
Expand Down
5 changes: 5 additions & 0 deletions src/bundler/Graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ pub struct Graph<'a> {
///
/// Helps skip a loop.
pub(crate) has_any_secondary_paths: bool,

/// The browser-variant `bun:runtime` of the browser side of a server-side
/// build. `Index::INVALID` when the build has no browser side.
Comment thread
robobun marked this conversation as resolved.
Resolved
pub(crate) browser_runtime: Index,
}

#[derive(Default)]
Expand Down Expand Up @@ -179,6 +183,7 @@ impl<'a> Graph<'a> {
kit_referenced_server_data: false,
kit_referenced_client_data: false,
has_any_secondary_paths: false,
browser_runtime: Index::INVALID,
}
}
}
Expand Down
248 changes: 163 additions & 85 deletions src/bundler/LinkerContext.rs

Large diffs are not rendered by default.

72 changes: 66 additions & 6 deletions src/bundler/LinkerGraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,9 @@ pub struct LinkerGraph<'a> {

pub(crate) code_splitting: bool,

/// See `Graph::browser_runtime`. Copied from the parse graph in `link`.
pub(crate) browser_runtime: Index,

// This is an alias from Graph
// it is not a clone!
pub(crate) ast: MultiArrayList<JSAst<'a>>,
Expand Down Expand Up @@ -312,6 +315,7 @@ impl Default for LinkerGraph<'_> {
// dangling sentinel (never read before assignment).
bump: bun_ptr::BackRef::from(core::ptr::NonNull::dangling()),
code_splitting: false,
browser_runtime: Index::INVALID,
ast: MultiArrayList::default(),
meta: MultiArrayList::default(),
reachable_files: Vec::new(),
Expand All @@ -334,8 +338,12 @@ impl Default for LinkerGraph<'_> {
// thin forwarders for call sites that don't have a split in hand.
// ──────────────────────────────────────────────────────────────────────────

fn runtime_function(named_exports: &[bundled_ast::NamedExports], name: &[u8]) -> Ref {
named_exports[Index::RUNTIME.get() as usize]
fn runtime_function(
named_exports: &[bundled_ast::NamedExports],
runtime: Index,
name: &[u8],
) -> Ref {
named_exports[runtime.get() as usize]
.get(name)
.expect("runtime function must be a named export of the runtime module")
.ref_
Expand Down Expand Up @@ -517,9 +525,60 @@ pub(crate) fn generate_symbol_import_and_use(
Ok(())
}

/// See [`LinkerGraph::is_runtime`], for callers that hold split-borrowed columns.
#[inline]
pub(crate) fn is_runtime(browser_runtime: Index, source_index: index::Int) -> bool {
source_index == Index::RUNTIME.get()
|| (browser_runtime.is_valid() && source_index == browser_runtime.get())
}

/// See [`LinkerGraph::runtime_index_for_target`].
#[inline]
pub(crate) fn runtime_index_for_target(browser_runtime: Index, target: bun_ast::Target) -> Index {
if browser_runtime.is_valid() && target == bun_ast::Target::Browser {
browser_runtime
} else {
Index::RUNTIME
}
}

impl<'a> LinkerGraph<'a> {
pub(crate) fn runtime_function(&self, name: &[u8]) -> Ref {
runtime_function(self.ast.items_named_exports(), name)
/// Whether `source_index` is one of the `bun:runtime` modules.
#[inline]
pub(crate) fn is_runtime(&self, source_index: index::Int) -> bool {
is_runtime(self.browser_runtime, source_index)
}

/// Every `bun:runtime` module in the graph, the main one first.
#[inline]
pub(crate) fn runtimes(&self) -> impl Iterator<Item = index::Int> {
core::iter::once(Index::RUNTIME.get()).chain(
self.browser_runtime
.is_valid()
.then(|| self.browser_runtime.get()),
)
}

/// The `bun:runtime` module that `source_index` links against, the same one
/// `BundleV2::runtime_source_index` gave its `bun:wrap` import records.
Comment thread
robobun marked this conversation as resolved.
Resolved
#[inline]
pub(crate) fn runtime_index(&self, source_index: index::Int) -> Index {
self.runtime_index_for_target(self.ast.items_target()[source_index as usize])
}

/// See [`Self::runtime_index`].
#[inline]
pub(crate) fn runtime_index_for_target(&self, target: bun_ast::Target) -> Index {
runtime_index_for_target(self.browser_runtime, target)
}

/// The symbol for the runtime export `name` that `source_index` links against.
pub(crate) fn runtime_function(&self, source_index: index::Int, name: &[u8]) -> Ref {
runtime_function(
self.ast.items_named_exports(),
self.runtime_index(source_index),
name,
)
}

/// Shared-ref view of a symbol that is known to exist (the `Ref` was
Expand Down Expand Up @@ -592,13 +651,14 @@ impl<'a> LinkerGraph<'a> {
source_index
);

let ref_ = self.runtime_function(name);
let runtime = self.runtime_index(source_index);
let ref_ = runtime_function(self.ast.items_named_exports(), runtime, name);
self.generate_symbol_import_and_use(
source_index,
entry_point_part_index.get(),
ref_,
count,
Index::RUNTIME,
runtime,
)
}

Expand Down
1 change: 0 additions & 1 deletion src/bundler/OutputFile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ impl OutputFile {
#[derive(Default, Clone, Copy)]
pub struct BakeExtra {
pub route: BakeRouteKind,
pub bake_is_runtime: bool,
}

#[derive(Default, Clone, Copy, PartialEq, Eq)]
Expand Down
46 changes: 29 additions & 17 deletions src/bundler/ParseTask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,11 +319,23 @@ impl ParseTask {
/// Re-export of `parse_worker::get_runtime_source` as an associated fn so
/// callers can spell it `ParseTask::get_runtime_source`.
#[inline]
pub(crate) fn get_runtime_source(target: options::Target) -> RuntimeSource {
parse_worker::get_runtime_source(target)
pub(crate) fn get_runtime_source(
target: options::Target,
source_index: Index,
) -> RuntimeSource {
parse_worker::get_runtime_source(target, source_index)
}

/// The task parses a `bun:runtime` module (a build can have two of them).
#[inline]
pub(crate) fn is_runtime(&self) -> bool {
self.path.namespace == RUNTIME_NAMESPACE
}
}

/// `Path.namespace` of every `bun:runtime` source.
pub(crate) const RUNTIME_NAMESPACE: &[u8] = b"bun:runtime";

impl Default for ParseTask {
fn default() -> Self {
ParseTask {
Expand Down Expand Up @@ -567,7 +579,7 @@ export var __callDispose = (stack, error, hasError) => {
pub mod parse_worker {
use super::*;

fn get_runtime_source_comptime(target: options::Target) -> RuntimeSource {
fn get_runtime_source_comptime(target: options::Target, source_index: Index) -> RuntimeSource {
// The runtime module is the shared `runtime.js` body plus a per-target
// `__require`/`__using` tail. Concatenating at compile time would embed
// four copies of the 13 KB body, so each variant is assembled once on
Expand Down Expand Up @@ -610,14 +622,14 @@ pub mod parse_worker {

let parse_task = ParseTask {
ctx: None,
path: Fs::Path::init_with_namespace(b"runtime", b"bun:runtime"),
path: Fs::Path::init_with_namespace(b"runtime", RUNTIME_NAMESPACE),
side_effects: bun_ast::SideEffects::NoSideEffectsPureData,
jsx: options::jsx::Pragma {
parse: false,
..Default::default()
},
contents_or_fd: ContentsOrFd::Contents(runtime_code),
source_index: Index::RUNTIME,
source_index,
loader: Some(Loader::Js),
known_target: target,
// defaults:
Expand Down Expand Up @@ -647,22 +659,23 @@ pub mod parse_worker {
// directly rather than `clone()` across the type boundary.
path: bun_paths::fs::Path {
text: b"runtime",
namespace: b"bun:runtime",
namespace: RUNTIME_NAMESPACE,
pretty: b"",
is_disabled: false,
is_symlink: false,
},
contents: std::borrow::Cow::Borrowed(runtime_code),
// `Source.index` is `bun_ast::Index` (newtype `u32`),
// distinct from `bun_ast::Index`. Runtime source is index 0.
index: bun_ast::Index(Index::RUNTIME.get()),
index: bun_ast::Index(source_index.get()),
..Default::default()
};
RuntimeSource { parse_task, source }
}

pub(crate) fn get_runtime_source(target: options::Target) -> RuntimeSource {
get_runtime_source_comptime(target)
pub(crate) fn get_runtime_source(
target: options::Target,
source_index: Index,
) -> RuntimeSource {
get_runtime_source_comptime(target, source_index)
}

// ───────────────────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -1629,7 +1642,7 @@ pub mod parse_worker {
from_plugin: &mut bool,
) -> core::result::Result<CacheEntry, AnyError> {
let might_have_on_parse_plugins = 'brk: {
if task.source_index.is_runtime() {
if task.is_runtime() {
break 'brk false;
}
// SAFETY: ctx backref is valid for the bundle pass (outlives `'r`).
Expand Down Expand Up @@ -2518,7 +2531,7 @@ pub mod parse_worker {
};
opts.package_version = task.package_version.slice();

opts.features.allow_runtime = !task.source_index.is_runtime();
opts.features.allow_runtime = !task.is_runtime();
opts.features.unwrap_commonjs_to_esm =
output_format == options::Format::Esm && FeatureFlags::UNWRAP_COMMONJS_TO_ESM;
opts.features.top_level_await = output_format == options::Format::Esm
Expand Down Expand Up @@ -2561,7 +2574,7 @@ pub mod parse_worker {
// targeting Bun there is no need to lower them.
opts.features.lower_using = !target.is_bun();
opts.features.hot_module_reloading =
output_format == options::Format::InternalBakeDev && !task.source_index.is_runtime();
output_format == options::Format::InternalBakeDev && !task.is_runtime();
opts.features.auto_polyfill_require =
output_format == options::Format::Esm && !opts.features.hot_module_reloading;
opts.features.react_fast_refresh =
Expand Down Expand Up @@ -2678,8 +2691,7 @@ pub mod parse_worker {
}
}

opts.ignore_dce_annotations =
topts.ignore_dce_annotations && !task.source_index.is_runtime();
opts.ignore_dce_annotations = topts.ignore_dce_annotations && !task.is_runtime();

// For files that are not user-specified entrypoints, set `import.meta.main` to `false`.
// Entrypoints will have `import.meta.main` set as "unknown", unless we use `--compile`,
Expand All @@ -2690,7 +2702,7 @@ pub mod parse_worker {
opts.lower_import_meta_main_for_node_js = true;
}

opts.tree_shaking = if task.source_index.is_runtime() {
opts.tree_shaking = if task.is_runtime() {
true
} else {
topts.tree_shaking
Expand Down
Loading
Loading