Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 2 additions & 0 deletions src/codegen/bundle-modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,8 @@ function idToEnumName(id: string) {

function idToPublicSpecifierOrEnumName(id: string) {
if (id === "internal-for-testing.ts") return "bun:internal-for-testing"; // not in the `bun/` folder because it's added conditionally
// The undici shim only stands in for the npm package (HardcodedModule.rs `Alias::fallback`), so its key is not the package name.
if (id === "thirdparty/undici.js") return "internal:undici";
id = id.replace(/\.[mc]?[tj]s$/, "");
if (id.startsWith("node/")) {
return "node:" + id.slice(5).replaceAll(".", "/");
Expand Down
8 changes: 4 additions & 4 deletions src/js/internal/repl/node-shims.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,11 @@ let builtinLibs;

function getBuiltinLibs() {
if (!builtinLibs) {
// Bun's builtinModules also lists `bun`, `bun:*`, `undici`, `ws`; none
// resolve under `node:`, so exclude them so completion and the REPL
// global scope match Node's.
// Bun's builtinModules also lists `bun`, `bun:*`, `ws`; none resolve
// under `node:`, so exclude them so completion and the REPL global
// scope match Node's.
Comment thread
robobun marked this conversation as resolved.
Resolved
builtinLibs = Module.builtinModules.filter(
id => !id.startsWith("_") && !id.startsWith("node:") && !id.startsWith("bun") && id !== "undici" && id !== "ws",
id => !id.startsWith("_") && !id.startsWith("node:") && !id.startsWith("bun") && id !== "ws",
);
}
return builtinLibs;
Expand Down
2 changes: 1 addition & 1 deletion src/js/internal/repl/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ function getREPLResourceName() {
const globalBuiltins = new SafeSet(vm.runInNewContext("Object.getOwnPropertyNames(globalThis)"));

// node-shims' getBuiltinLibs() also excludes Bun-specific entries (`bun*`,
// `undici`, `ws`) so completion doesn't offer e.g. `node:undici`.
// `ws`) so completion doesn't offer e.g. `node:ws`.
let _builtinLibs = getBuiltinLibs().slice();

// Note: the `getReplBuiltinLibs` and `setReplBuiltinLibs` are functions used to provide getters and
Expand Down
3 changes: 2 additions & 1 deletion src/jsc/RuntimeTranspilerCache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ bun_core::declare_scope!(cache, visible);
/// Version 28: the define table and `--drop` entries participate in the features hash.
/// Version 29: `new Array(x, ...spread)` is no longer folded into an array literal.
/// Version 30: String enum members are stored flat, so folds no longer append onto an inlined member.
const EXPECTED_VERSION: u32 = 30;
/// Version 31: `next/dist/compiled/undici` is rewritten to `internal:undici`, no longer `undici`.
const EXPECTED_VERSION: u32 = 31;

/// Source files smaller than this are not written to / read from the on-disk
/// transpiler cache. Originally 50 KiB, which excluded almost every file in a
Expand Down
1 change: 0 additions & 1 deletion src/jsc/bindings/isBuiltinModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ static constexpr ASCIILiteral builtinModuleNamesSortedLength[] = {
"module"_s,
"stream"_s,
"timers"_s,
"undici"_s,
"bun:ffi"_s,
"bun:jsc"_s,
"cluster"_s,
Expand Down
1 change: 0 additions & 1 deletion src/jsc/modules/NodeModuleModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ static constexpr ASCIILiteral builtinModuleNames[] = {
"tls"_s,
"trace_events"_s,
"tty"_s,
"undici"_s,
"url"_s,
Comment thread
robobun marked this conversation as resolved.
Resolved
"util"_s,
"util/types"_s,
Expand Down
20 changes: 16 additions & 4 deletions src/resolve_builtins/HardcodedModule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub enum HardcodedModule {
NodeWorkerThreads,
#[strum(serialize = "node:punycode")]
NodePunycode,
#[strum(serialize = "undici")]
#[strum(serialize = "internal:undici")]
Undici,
#[strum(serialize = "ws")]
Ws,
Expand Down Expand Up @@ -297,7 +297,7 @@ bun_core::comptime_string_map! {

b"node-fetch" => HardcodedModule::NodeFetch,
b"isomorphic-fetch" => HardcodedModule::IsomorphicFetch,
b"undici" => HardcodedModule::Undici,
b"internal:undici" => HardcodedModule::Undici,
b"ws" => HardcodedModule::Ws,
b"@vercel/fetch" => HardcodedModule::VercelFetch,
b"utf-8-validate" => HardcodedModule::Utf8Validate,
Expand Down Expand Up @@ -747,7 +747,8 @@ const BUN_EXTRA_ALIAS_KVS: &[AliasKv] = &[
entry!("@vercel/fetch"),
entry!("isomorphic-fetch"),
entry!("node-fetch"),
entry!("undici"),
// Fallback only (`Alias::fallback`); not the npm name, so the key never re-resolves into node_modules.
entry!("internal:undici"),
entry!("utf-8-validate"),
entry!("ws"),
(
Expand Down Expand Up @@ -794,7 +795,7 @@ const BUN_EXTRA_ALIAS_KVS: &[AliasKv] = &[
(
b"next/dist/compiled/undici",
Alias {
path: zstr!("undici"),
path: zstr!("internal:undici"),
tag: import_record::Tag::Builtin,
node_builtin: false,
node_only_prefix: false,
Expand Down Expand Up @@ -920,6 +921,17 @@ impl Alias {
Self::get(name, target, cfg).is_some()
}

/// The builtin that stands in for `name` when node_modules resolution fails (#36098).
pub fn fallback(name: &[u8], target: Target) -> Option<Alias> {
if !target.is_bun() {
return None;
}
match name {
b"undici" => Self::get(b"internal:undici", target, Cfg::default()),
_ => None,
}
}

pub fn get(name: &[u8], target: Target, cfg: Cfg) -> Option<Alias> {
// Without `--experimental-stream-iter` the aliases stay invisible so
// the bare specifier falls through to filesystem resolution
Expand Down
63 changes: 59 additions & 4 deletions src/resolver/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1358,8 +1358,28 @@ impl<'a> Resolver<'a> {
return ResultUnion::NotFound;
}

let mut tmp =
self.resolve_without_symlinks(source_dir_normalized, import_path, kind, global_cache);
// Probe without auto-install; the builtin stands in when nothing is installed.
let fallback = HardcodedAlias::fallback(import_path, self.opts.target);
let mut tmp = self.resolve_without_symlinks(
source_dir_normalized,
import_path,
kind,
if fallback.is_some() {
GlobalCache::disable
} else {
global_cache
},
);
if let Some(fallback) = fallback {
if matches!(tmp, ResultUnion::NotFound) {
let _ = self.flush_debug_logs(FlushMode::Success);
self.extension_order = original_order;
return ResultUnion::Success(Self::external_builtin(
fallback.path.as_bytes(),
kind,
));
}
}

// Fragments in URLs in CSS imports are technically expected to work
if matches!(tmp, ResultUnion::NotFound) && kind.is_from_css() {
Expand Down Expand Up @@ -1451,6 +1471,21 @@ impl<'a> Resolver<'a> {
ret
}

/// An external result that rewrites the import to the builtin `path`.
fn external_builtin(path: &'static [u8], kind: ast::ImportKind) -> Result {
Result {
import_kind: kind,
path_pair: PathPair {
primary: Path::init(path),
secondary: None,
},
module_type: options::ModuleType::Cjs,
primary_side_effects_data: SideEffects::NoSideEffectsPureData,
flags: ResultFlags::IS_EXTERNAL | ResultFlags::REWRITE_IMPORT_PATH,
..Default::default()
}
}

pub fn resolve(
&mut self,
source_dir: &[u8],
Expand Down Expand Up @@ -5022,14 +5057,34 @@ impl<'a> Resolver<'a> {
}
}

return self.load_node_modules(
// As in `resolve_and_auto_install`: probe without auto-install, then fall back.
let fallback = HardcodedAlias::fallback(&esm_resolution.path, self.opts.target);
let status = self.load_node_modules(
&esm_resolution.path,
kind,
dir_info,
global_cache,
if fallback.is_some() {
GlobalCache::disable
} else {
global_cache
},
true,
out,
);
if let Some(fallback) = fallback {
if matches!(status, MatchStatus::NotFound) {
*out = MatchResult {
path_pair: PathPair {
primary: Fs::Path::init(fallback.path.as_bytes()),
secondary: None,
},
is_external: true,
..Default::default()
};
return MatchStatus::Success;
}
}
return status;
}

self.handle_esm_resolution(
Expand Down
6 changes: 3 additions & 3 deletions test/bundler/bundler_bytecode_portable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -514,10 +514,10 @@ describe("bytecode cache portability", () => {
},
},
"bun build --bytecode libraries.js": {
"js": "493bab674ff49b287f26be3f356a3ad6681afb0c7eeffaa590f10cdcd8b58724",
"js": "e143c4f3946997a36432a5208ccee1f81d27235b37dcfdf3d6c3b7ba24269d7b",
"jsc": {
"bytes": 23772944,
"sha256": "c0bb1ca0664a9c7146fadb951e4f6f801811918489f5777fdbbda101a6ffd6c6",
"bytes": 24856912,
"sha256": "51854d56d6f4f107b5b1dc21d7704b585f06401e3dda6d9f976a762093cf1de0",
},
},
"bun build --bytecode lodash/lodash.js": {
Expand Down
4 changes: 3 additions & 1 deletion test/js/bun/util/fuzzy-wuzzy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,9 @@ const modules = [
"_http_server",
"http2",
"process",
"undici",
// Bun's undici shim. Bare "undici" resolves to the installed package when
// present; this alias always maps to the shim.
"next/dist/compiled/undici",
"timers",
"punycode",
"trace_events",
Expand Down
Loading
Loading