Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
5 changes: 5 additions & 0 deletions src/ast/e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ pub struct Super;
#[derive(Clone, Copy, Default)]
pub struct ImportMeta;

impl ImportMeta {
/// Sixth parameter of the CommonJS wrapper. JSCommonJSModule.cpp passes `import.meta` for it.
pub const CJS_WRAPPER_ARG: &'static [u8] = b"$Bun_import_meta";
}

#[derive(Clone, Copy, Default)]
pub struct ImportMetaMain {
/// If true, print `!import.meta.main` (or `require.main != module`).
Expand Down
8 changes: 8 additions & 0 deletions src/bundler/LinkerContext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2313,6 +2313,12 @@ impl<'a> LinkerContext<'a> {
Ok(true)
}

/// The one place that decides whether a chunk gets the `@bun-cjs` function wrapper.
pub(crate) fn chunk_has_bun_cjs_wrapper(&self, chunk: &Chunk) -> bool {
self.options.output_format == Format::Cjs
&& self.graph.ast.items_target()[chunk.entry_point.source_index() as usize].is_bun()
}

pub(crate) fn print_code_for_file_in_chunk_js(
&mut self,
r: renamer::Renamer,
Expand All @@ -2324,6 +2330,7 @@ impl<'a> LinkerContext<'a> {
to_esm_ref: Ref,
to_commonjs_ref: Ref,
runtime_require_ref: Option<Ref>,
inside_bun_cjs_wrapper: bool,
source_index: Index,
source: &Source,
module_info: Option<&mut crate::analyze_transpiled_module::ModuleInfo>,
Expand Down Expand Up @@ -2403,6 +2410,7 @@ impl<'a> LinkerContext<'a> {
Format::Cjs => None, // use unbounded global
_ => runtime_require_ref,
},
inside_bun_cjs_wrapper,
require_or_import_meta_for_source_callback:
js_printer::RequireOrImportMetaCallback::init(self),
line_offset_tables: Some(line_offset_table),
Expand Down
4 changes: 4 additions & 0 deletions src/bundler/ParseTask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2639,6 +2639,10 @@ pub mod parse_worker {
opts.lower_import_meta_main_for_node_js = true;
}

// For bun, cjs output gets import.meta from the `@bun-cjs` wrapper instead.
opts.inline_import_meta_paths = topts.framework.is_some()
|| (output_format == options::Format::Cjs && !target.is_bun());
Comment thread
robobun marked this conversation as resolved.
Resolved
Comment thread
robobun marked this conversation as resolved.
Resolved

opts.tree_shaking = if task.source_index.is_runtime() {
true
} else {
Expand Down
7 changes: 3 additions & 4 deletions src/bundler/bundle_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7766,10 +7766,9 @@ pub mod bv2_impl {
fn default() -> Self {
CompileResult::Javascript {
source_index: 0,
result: bun_js_printer::PrintResult::Result(bun_js_printer::PrintResultSuccess {
code: Box::new([]),
source_map: None,
}),
result: bun_js_printer::PrintResult::Result(
bun_js_printer::PrintResultSuccess::default(),
),
module_info: None,
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/bundler/linker_context/generateCodeForFileInChunkJS.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub fn generate_code_for_file_in_chunk_js<'r, 'src>(
to_common_js_ref: Ref,
to_esm_ref: Ref,
runtime_require_ref: Option<Ref>,
inside_bun_cjs_wrapper: bool,
stmts: &mut StmtList,
arena: &Bump,
temp_arena: &Bump,
Expand Down Expand Up @@ -226,6 +227,7 @@ pub fn generate_code_for_file_in_chunk_js<'r, 'src>(
Ref::NONE,
Ref::NONE,
None,
false,
part_range.source_index,
source,
module_info,
Expand Down Expand Up @@ -967,10 +969,7 @@ pub fn generate_code_for_file_in_chunk_js<'r, 'src>(
let out_stmts: &mut [Stmt] = out_stmts.slice_mut();

if out_stmts.is_empty() {
return PrintResult::Result(PrintResultSuccess {
code: Box::new([]),
source_map: None,
});
return PrintResult::Result(PrintResultSuccess::default());
}

// `get_source` returns `&'static Source` (parse_graph SoA is append-only and
Expand All @@ -987,6 +986,7 @@ pub fn generate_code_for_file_in_chunk_js<'r, 'src>(
to_esm_ref,
to_common_js_ref,
runtime_require_ref,
inside_bun_cjs_wrapper,
part_range.source_index,
source,
module_info,
Expand Down
2 changes: 2 additions & 0 deletions src/bundler/linker_context/generateCompileResultForJSChunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ fn generate_compile_result_for_js_chunk_impl(
.follow(runtime_members.get(b"__require".as_slice()).unwrap().ref_),
)
};
let inside_bun_cjs_wrapper = c.chunk_has_bun_cjs_wrapper(chunk);

// `worker.arena` (= `BackRef` to `worker.heap`) is a disjoint field from
// `worker.temporary_arena` / `worker.stmt_list` borrowed `&mut` above, so
Expand Down Expand Up @@ -149,6 +150,7 @@ fn generate_compile_result_for_js_chunk_impl(
to_common_js_ref,
to_esm_ref,
runtime_require_ref,
inside_bun_cjs_wrapper,
stmt_list,
worker_alloc,
&**arena,
Expand Down
55 changes: 34 additions & 21 deletions src/bundler/linker_context/postProcessJSChunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,18 @@ fn module_preload_registration(
Ok(code)
}

fn chunk_uses_import_meta_arg(chunk: &Chunk) -> bool {
chunk.compile_results_for_chunk.iter().any(|result| {
matches!(
result,
CompileResult::Javascript {
result: PrintResult::Result(printed),
..
} if printed.uses_import_meta_arg
)
})
}

/// This runs after we've already populated the compile results
pub(crate) fn post_process_js_chunk(
ctx: GenerateChunkCtx,
Expand Down Expand Up @@ -361,10 +373,7 @@ pub(crate) fn post_process_js_chunk(

break 'brk CompileResult::Javascript {
source_index: Index::INVALID.value(),
result: PrintResult::Result(js_printer::PrintResultSuccess {
code: Box::default(),
source_map: None,
}),
result: PrintResult::Result(js_printer::PrintResultSuccess::default()),
module_info: None,
};
};
Expand Down Expand Up @@ -441,20 +450,27 @@ pub(crate) fn post_process_js_chunk(

// Add @bun comments and CJS wrapper start for each chunk when targeting Bun.
let is_bun = c.graph.ast.items_target()[chunk.entry_point.source_index() as usize].is_bun();
if is_bun {
if c.options.generate_bytecode_cache && output_format == options::OutputFormat::Cjs {
const INPUT: &[u8] =
b"// @bun @bytecode @bun-cjs\n(function(exports, require, module, __filename, __dirname) {";
j.push_static(INPUT);
line_offset.advance(INPUT);
} else if c.options.generate_bytecode_cache {
let has_bun_cjs_wrapper = c.chunk_has_bun_cjs_wrapper(chunk);
if has_bun_cjs_wrapper {
let mut push = |bytes: &'static [u8]| {
j.push_static(bytes);
line_offset.advance(bytes);
};
push(if c.options.generate_bytecode_cache {
b"// @bun @bytecode @bun-cjs\n"
} else {
b"// @bun @bun-cjs\n"
});
push(b"(function(exports, require, module, __filename, __dirname");
if chunk_uses_import_meta_arg(chunk) {
push(b", ");
push(E::ImportMeta::CJS_WRAPPER_ARG);
}
push(b") {");
} else if is_bun {
if c.options.generate_bytecode_cache {
j.push_static(b"// @bun @bytecode\n");
line_offset.advance(b"// @bun @bytecode\n");
} else if output_format == options::OutputFormat::Cjs {
const INPUT: &[u8] =
b"// @bun @bun-cjs\n(function(exports, require, module, __filename, __dirname) {";
j.push_static(INPUT);
line_offset.advance(INPUT);
} else {
j.push_static(b"// @bun\n");
line_offset.advance(b"// @bun\n");
Expand Down Expand Up @@ -749,7 +765,7 @@ pub(crate) fn post_process_js_chunk(
}
}
options::OutputFormat::Cjs => {
if is_bun {
if has_bun_cjs_wrapper {
j.push_static(b"})\n");
line_offset.advance(b"})\n");
}
Expand Down Expand Up @@ -1260,10 +1276,7 @@ pub(crate) fn generate_entry_point_tail_js<'a>(
if stmts.is_empty() {
return CompileResult::Javascript {
source_index,
result: PrintResult::Result(js_printer::PrintResultSuccess {
code: Box::default(),
source_map: None,
}),
result: PrintResult::Result(js_printer::PrintResultSuccess::default()),
module_info: None,
};
}
Expand Down
5 changes: 5 additions & 0 deletions src/bundler/linker_context/renameSymbolsInChunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ pub(crate) unsafe fn rename_symbols_in_chunk(
// borrow does not assert immutability over the heap cells written below.
// SAFETY: see fn safety doc — `c` is live for the call.
let c: &LinkerContext<'_> = unsafe { &*c };
let has_bun_cjs_wrapper = c.chunk_has_bun_cjs_wrapper(chunk);

// ── raw SoA column pointers (root provenance) ────────────────────────
// `split_raw()` derives `*mut [T]` directly from the buffer base with no
Expand Down Expand Up @@ -144,6 +145,10 @@ pub(crate) unsafe fn rename_symbols_in_chunk(
};

let mut reserved_names = renamer::compute_initial_reserved_names(c.options.output_format)?;
if has_bun_cjs_wrapper {
// The printer refers to this wrapper parameter by name.
reserved_names.put(bun_ast::E::ImportMeta::CJS_WRAPPER_ARG, 1)?;
}
for &source_index in files_in_order {
renamer::compute_reserved_names_for_scope(
&all_module_scopes[source_index as usize],
Expand Down
1 change: 1 addition & 0 deletions src/bundler/transpiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1598,6 +1598,7 @@ impl<'a> Transpiler<'a> {
transform_only: self.options.transform_only,
import_meta_main_value: None,
lower_import_meta_main_for_node_js: false,
inline_import_meta_paths: false,
framework: None,
repl_mode: self.options.repl_mode,
lower_toml_datetimes: false,
Expand Down
8 changes: 2 additions & 6 deletions src/js_parser/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use bun_collections::VecExt;
use bun_core::feature_flags as FeatureFlags;

use crate::p::P;
use crate::parser::{self as js_parser, IdentifierOpts, RelocateVars, RelocateVarsMode};
use crate::parser::{IdentifierOpts, RelocateVars, RelocateVarsMode};
use bun_ast::ast_result::CommonJSNamedExport;
use bun_ast::{self as js_ast, Binding, E, Expr, Flags, G, LocRef, S};

Expand Down Expand Up @@ -599,11 +599,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
});
}

// Inline import.meta properties for Bake
if p.options.framework.is_some()
|| (p.options.bundle
&& p.options.output_format == js_parser::options::Format::Cjs)
{
if p.options.inline_import_meta_paths {
if name == b"dir" || name == b"dirname" {
// Inline import.meta.dir
return Some(
Expand Down
2 changes: 1 addition & 1 deletion src/js_parser/p.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9144,7 +9144,7 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
};
if self.has_import_meta {
self.import_meta_ref =
self.new_symbol(js_ast::symbol::Kind::Other, b"$Bun_import_meta");
self.new_symbol(js_ast::symbol::Kind::Other, E::ImportMeta::CJS_WRAPPER_ARG);
args[5] = Arg {
binding: self.b(
B::Identifier {
Expand Down
6 changes: 6 additions & 0 deletions src/js_parser/parse/parse_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ pub struct Options<'a> {
pub import_meta_main_value: Option<bool>,
pub lower_import_meta_main_for_node_js: bool,

/// Inline the source file's paths for `import.meta.dir`, `.dirname`, `.file`, `.path`, `.url`.
pub inline_import_meta_paths: bool,

/// When using react fast refresh or server components, the framework is
/// able to customize what import sources are used.
pub framework: Option<&'a options::Framework>, // TYPE_ONLY: was bun_runtime::bake::Framework
Expand Down Expand Up @@ -142,6 +145,7 @@ impl<'a> Default for Options<'a> {
transform_only: false,
import_meta_main_value: None,
lower_import_meta_main_for_node_js: false,
inline_import_meta_paths: false,
framework: None,
repl_mode: false,
lower_toml_datetimes: false,
Expand Down Expand Up @@ -228,6 +232,7 @@ impl<'a> Options<'a> {
transform_only: self.transform_only,
import_meta_main_value: self.import_meta_main_value,
lower_import_meta_main_for_node_js: self.lower_import_meta_main_for_node_js,
inline_import_meta_paths: self.inline_import_meta_paths,
framework: self.framework,
repl_mode: self.repl_mode,
lower_toml_datetimes: self.lower_toml_datetimes,
Expand Down Expand Up @@ -301,6 +306,7 @@ impl<'a> Options<'a> {
transform_only: false,
import_meta_main_value: None,
lower_import_meta_main_for_node_js: false,
inline_import_meta_paths: false,
framework: None,
repl_mode: false,
lower_toml_datetimes: loader == options::Loader::Toml,
Expand Down
32 changes: 20 additions & 12 deletions src/js_printer/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,8 @@ pub struct Options<'a> {
pub module_preload_ref: Ref,
pub require_ref: Option<Ref>,
pub import_meta_ref: Ref,
/// Print `import.meta` as `E::ImportMeta::CJS_WRAPPER_ARG`, a parameter of the `@bun-cjs` wrapper.
pub inside_bun_cjs_wrapper: bool,
pub hmr_ref: Ref,
pub indent: Indentation,
// allocator dropped — global mimalloc (this is an AST crate but Options.allocator is the global default)
Expand Down Expand Up @@ -1408,6 +1410,7 @@ impl<'a> Default for Options<'a> {
module_preload_ref: Ref::NONE,
require_ref: None,
import_meta_ref: Ref::NONE,
inside_bun_cjs_wrapper: false,
hmr_ref: Ref::NONE,
indent: Indentation::default(),
source_map_handler: None,
Expand Down Expand Up @@ -1553,9 +1556,12 @@ pub enum PrintResult {
Err(crate::Error),
}

#[derive(Default)]
pub struct PrintResultSuccess {
pub code: Box<[u8]>,
pub source_map: Option<SourceMap::Chunk>,
/// `code` refers to `E::ImportMeta::CJS_WRAPPER_ARG` (see `Options::inside_bun_cjs_wrapper`).
pub uses_import_meta_arg: bool,
}

// do not make this a packed struct
Expand Down Expand Up @@ -1677,6 +1683,7 @@ pub(crate) mod __gated_printer {
pub(crate) stack_overflowed: bool,

pub(crate) was_lazy_export: bool,
pub(crate) uses_import_meta_arg: bool,
// Always carried; gated at call sites with MAY_HAVE_MODULE_INFO.
pub(crate) module_info: Option<&'a mut analyze_transpiled_module::ModuleInfo>,

Expand Down Expand Up @@ -3290,23 +3297,22 @@ pub(crate) mod __gated_printer {
debug_assert!(self.options.hmr_ref.is_valid());
self.print_symbol(self.options.hmr_ref);
self.print(b".importMeta");
} else if !self.options.import_meta_ref.is_valid() {
// Most of the time, leave it in there
if let Some(mi) = self.module_info() {
mi.flags.contains_import_meta = true;
}
self.print(b"import.meta");
} else {
// Note: The bundler will not hit this code path. The bundler will replace
// the ImportMeta AST node with a regular Identifier AST node.
//
// This is currently only used in Bun's runtime for CommonJS modules
// referencing import.meta
} else if self.options.import_meta_ref.is_valid() {
// The runtime's CommonJS wrapper (`WrapMode::BunCommonjs`).
//
// TODO: This assertion trips when using `import.meta` with `--format=cjs`
debug_assert!(self.options.module_type == bundle_opts::Format::Cjs);

self.print_symbol(self.options.import_meta_ref);
} else if self.options.inside_bun_cjs_wrapper {
self.print(E::ImportMeta::CJS_WRAPPER_ARG);
self.uses_import_meta_arg = true;
} else {
// Most of the time, leave it in there
if let Some(mi) = self.module_info() {
mi.flags.contains_import_meta = true;
}
self.print(b"import.meta");
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
}
}
ExprData::EImportMetaMain(data) => {
Expand Down Expand Up @@ -7026,6 +7032,7 @@ pub(crate) mod __gated_printer {
stack_check: bun_core::StackCheck::init(),
stack_overflowed: false,
was_lazy_export: false,
uses_import_meta_arg: false,
module_info: None,
}
}
Expand Down Expand Up @@ -8230,6 +8237,7 @@ pub(crate) fn print_with_writer_and_platform<
PrintResult::Result(PrintResultSuccess {
code: buffer.take_slice().into(),
source_map,
uses_import_meta_arg: printer.uses_import_meta_arg,
})
}

Expand Down
Loading
Loading