From 0e372e3837802f7ebdafb2a1c128f28ee6c4ff95 Mon Sep 17 00:00:00 2001 From: BlankParticle Date: Sun, 12 Jul 2026 17:04:40 +0530 Subject: [PATCH 1/3] fix(cli): always append node path when spawning child pm process --- .../shim_bun_runs_node_child/package.json | 11 +++ .../shim_bun_runs_node_child/snapshots.toml | 8 ++ .../snapshots/shim_bun_runs_node_child.md | 13 +++ crates/vite_global_cli/src/shim/dispatch.rs | 92 +++++++++---------- 4 files changed, 75 insertions(+), 49 deletions(-) create mode 100644 crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/package.json create mode 100644 crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots.toml create mode 100644 crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots/shim_bun_runs_node_child.md diff --git a/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/package.json b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/package.json new file mode 100644 index 0000000000..07d2ce62be --- /dev/null +++ b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/package.json @@ -0,0 +1,11 @@ +{ + "name": "shim-bun-runs-node-child", + "private": true, + "scripts": { + "node-child": "node -v" + }, + "engines": { + "node": "22.12.0" + }, + "packageManager": "bun@1.3.11" +} diff --git a/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots.toml b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots.toml new file mode 100644 index 0000000000..0b7c9d78a3 --- /dev/null +++ b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots.toml @@ -0,0 +1,8 @@ +[[case]] +name = "shim_bun_runs_node_child" +vp = "global" +skip-platforms = ["windows"] +steps = [ + { argv = ["vp", "install", "-g", "bun"], snapshot = false }, + { argv = ["bun", "run", "node-child"], comment = "Bun scripts can invoke the managed Node runtime" }, +] diff --git a/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots/shim_bun_runs_node_child.md b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots/shim_bun_runs_node_child.md new file mode 100644 index 0000000000..ead2d24e07 --- /dev/null +++ b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots/shim_bun_runs_node_child.md @@ -0,0 +1,13 @@ +# shim_bun_runs_node_child + +## `vp install -g bun` + + +## `bun run node-child` + +Bun scripts can invoke the managed Node runtime + +``` +$ node -v + +``` diff --git a/crates/vite_global_cli/src/shim/dispatch.rs b/crates/vite_global_cli/src/shim/dispatch.rs index 47776f7a31..70e469e023 100644 --- a/crates/vite_global_cli/src/shim/dispatch.rs +++ b/crates/vite_global_cli/src/shim/dispatch.rs @@ -954,66 +954,60 @@ pub async fn dispatch(tool: &str, args: &[String]) -> i32 { /// Finds the package that provides this binary and executes it with the /// Node.js version that was used to install the package. async fn dispatch_package_binary(tool: &str, args: &[String]) -> i32 { - if let Some(pm_family) = PackageManagerType::from_tool(tool) { - let cwd = match current_dir() { - Ok(path) => path, - Err(e) => { - eprintln!("vp: Failed to get current directory: {e}"); - return 1; - } - }; + let cwd = match current_dir() { + Ok(path) => path, + Err(e) => { + eprintln!("vp: Failed to get current directory: {e}"); + return 1; + } + }; - match resolve_matching_package_manager_tool(&cwd, tool).await { - Ok(Some(tool_path)) => { - // Bun is a native binary and does not need a Node.js runtime on PATH; - // JS-based PMs (npm/pnpm/yarn) do. - if pm_family != PackageManagerType::Bun { - let node_version = match resolve_with_cache(&cwd).await { - Ok(resolution) => resolution.version, - Err(_) => match find_package_for_binary(tool).await { - Ok(Some(metadata)) => metadata.platform.node, - _ => String::new(), - }, - }; + match resolve_matching_package_manager_tool(&cwd, tool).await { + Ok(Some(tool_path)) => { + let node_version = match resolve_with_cache(&cwd).await { + Ok(resolution) => resolution.version, + Err(_) => match find_package_for_binary(tool).await { + Ok(Some(metadata)) => metadata.platform.node, + _ => String::new(), + }, + }; - if !node_version.is_empty() { - match ensure_installed(&node_version).await { - Ok(node_path) => { - if let Some(node_bin_dir) = node_path.parent() { - if let Err(e) = - prepend_js_child_process_path_env(&cwd, node_bin_dir).await - { - eprintln!( - "vp: Failed to resolve package manager for child \ + if !node_version.is_empty() { + match ensure_installed(&node_version).await { + Ok(node_path) => { + if let Some(node_bin_dir) = node_path.parent() { + if let Err(e) = + prepend_js_child_process_path_env(&cwd, node_bin_dir).await + { + eprintln!( + "vp: Failed to resolve package manager for child \ process PATH: {e}" - ); - return 1; - } - } - } - Err(e) => { - eprintln!("vp: Failed to install Node {}: {e}", node_version); + ); return 1; } } } + Err(e) => { + eprintln!("vp: Failed to install Node {}: {e}", node_version); + return 1; + } } + } - if let Some(pm_bin_dir) = tool_path.parent() { - let _ = prepend_to_path_env(pm_bin_dir, PrependOptions::default()); - } - - // SAFETY: Setting env vars at this point before exec is safe - unsafe { - std::env::set_var(RECURSION_ENV_VAR, "1"); - } - return exec::exec_tool(&tool_path, args); + if let Some(pm_bin_dir) = tool_path.parent() { + let _ = prepend_to_path_env(pm_bin_dir, PrependOptions::default()); } - Ok(None) => {} - Err(e) => { - eprintln!("vp: Failed to resolve package manager for '{tool}': {e}"); - return 1; + + // SAFETY: Setting env vars at this point before exec is safe + unsafe { + std::env::set_var(RECURSION_ENV_VAR, "1"); } + return exec::exec_tool(&tool_path, args); + } + Ok(None) => {} + Err(e) => { + eprintln!("vp: Failed to resolve package manager for '{tool}': {e}"); + return 1; } } From c631fbe25bf986376797ca0a47162a0d85faa282 Mon Sep 17 00:00:00 2001 From: BlankParticle Date: Sun, 12 Jul 2026 17:38:41 +0530 Subject: [PATCH 2/3] fix: only require cwd when tool is a package manager --- crates/vite_global_cli/src/shim/dispatch.rs | 90 +++++++++++---------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/crates/vite_global_cli/src/shim/dispatch.rs b/crates/vite_global_cli/src/shim/dispatch.rs index 70e469e023..18d608aedd 100644 --- a/crates/vite_global_cli/src/shim/dispatch.rs +++ b/crates/vite_global_cli/src/shim/dispatch.rs @@ -954,60 +954,62 @@ pub async fn dispatch(tool: &str, args: &[String]) -> i32 { /// Finds the package that provides this binary and executes it with the /// Node.js version that was used to install the package. async fn dispatch_package_binary(tool: &str, args: &[String]) -> i32 { - let cwd = match current_dir() { - Ok(path) => path, - Err(e) => { - eprintln!("vp: Failed to get current directory: {e}"); - return 1; - } - }; + if PackageManagerType::from_tool(tool).is_some() { + let cwd = match current_dir() { + Ok(path) => path, + Err(e) => { + eprintln!("vp: Failed to get current directory: {e}"); + return 1; + } + }; - match resolve_matching_package_manager_tool(&cwd, tool).await { - Ok(Some(tool_path)) => { - let node_version = match resolve_with_cache(&cwd).await { - Ok(resolution) => resolution.version, - Err(_) => match find_package_for_binary(tool).await { - Ok(Some(metadata)) => metadata.platform.node, - _ => String::new(), - }, - }; + match resolve_matching_package_manager_tool(&cwd, tool).await { + Ok(Some(tool_path)) => { + let node_version = match resolve_with_cache(&cwd).await { + Ok(resolution) => resolution.version, + Err(_) => match find_package_for_binary(tool).await { + Ok(Some(metadata)) => metadata.platform.node, + _ => String::new(), + }, + }; - if !node_version.is_empty() { - match ensure_installed(&node_version).await { - Ok(node_path) => { - if let Some(node_bin_dir) = node_path.parent() { - if let Err(e) = - prepend_js_child_process_path_env(&cwd, node_bin_dir).await - { - eprintln!( - "vp: Failed to resolve package manager for child \ + if !node_version.is_empty() { + match ensure_installed(&node_version).await { + Ok(node_path) => { + if let Some(node_bin_dir) = node_path.parent() { + if let Err(e) = + prepend_js_child_process_path_env(&cwd, node_bin_dir).await + { + eprintln!( + "vp: Failed to resolve package manager for child \ process PATH: {e}" - ); - return 1; + ); + return 1; + } } } - } - Err(e) => { - eprintln!("vp: Failed to install Node {}: {e}", node_version); - return 1; + Err(e) => { + eprintln!("vp: Failed to install Node {}: {e}", node_version); + return 1; + } } } - } - if let Some(pm_bin_dir) = tool_path.parent() { - let _ = prepend_to_path_env(pm_bin_dir, PrependOptions::default()); - } + if let Some(pm_bin_dir) = tool_path.parent() { + let _ = prepend_to_path_env(pm_bin_dir, PrependOptions::default()); + } - // SAFETY: Setting env vars at this point before exec is safe - unsafe { - std::env::set_var(RECURSION_ENV_VAR, "1"); + // SAFETY: Setting env vars at this point before exec is safe + unsafe { + std::env::set_var(RECURSION_ENV_VAR, "1"); + } + return exec::exec_tool(&tool_path, args); + } + Ok(None) => {} + Err(e) => { + eprintln!("vp: Failed to resolve package manager for '{tool}': {e}"); + return 1; } - return exec::exec_tool(&tool_path, args); - } - Ok(None) => {} - Err(e) => { - eprintln!("vp: Failed to resolve package manager for '{tool}': {e}"); - return 1; } } From 9fb01a7eaf4f4f2f6fde4e20c9f1240dbcd95702 Mon Sep 17 00:00:00 2001 From: BlankParticle Date: Sun, 12 Jul 2026 18:05:04 +0530 Subject: [PATCH 3/3] fix: apply codex suggestions --- .../fixtures/shim_bun_runs_node_child/package.json | 2 +- .../fixtures/shim_bun_runs_node_child/snapshots.toml | 1 - .../snapshots/shim_bun_runs_node_child.md | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/package.json b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/package.json index 07d2ce62be..a3554c0ab7 100644 --- a/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/package.json +++ b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/package.json @@ -2,7 +2,7 @@ "name": "shim-bun-runs-node-child", "private": true, "scripts": { - "node-child": "node -v" + "node-child": "node -e \"if (process.version !== 'v22.12.0') process.exit(1)\"" }, "engines": { "node": "22.12.0" diff --git a/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots.toml b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots.toml index 0b7c9d78a3..ece3ed0476 100644 --- a/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots.toml +++ b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots.toml @@ -1,7 +1,6 @@ [[case]] name = "shim_bun_runs_node_child" vp = "global" -skip-platforms = ["windows"] steps = [ { argv = ["vp", "install", "-g", "bun"], snapshot = false }, { argv = ["bun", "run", "node-child"], comment = "Bun scripts can invoke the managed Node runtime" }, diff --git a/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots/shim_bun_runs_node_child.md b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots/shim_bun_runs_node_child.md index ead2d24e07..3867dadb4c 100644 --- a/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots/shim_bun_runs_node_child.md +++ b/crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/shim_bun_runs_node_child/snapshots/shim_bun_runs_node_child.md @@ -8,6 +8,5 @@ Bun scripts can invoke the managed Node runtime ``` -$ node -v - +$ node -e "if (process.version !== '') process.exit(1)" ```