Skip to content
Closed
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
9 changes: 4 additions & 5 deletions crates/vite_global_cli/src/commands/env/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

use std::process::ExitStatus;

use vite_js_runtime::NodeProvider;
use vite_js_runtime::{NodeProvider, ensure_node_core_bin_prefix};
use vite_shared::{env_vars, format_path_prepended};

use crate::{
Expand Down Expand Up @@ -137,10 +137,9 @@ async fn execute_with_version(
std::env::remove_var(env_vars::VP_TOOL_RECURSION);
}

// 4. Build PATH with node bin dir first (uses platform-specific separator)
// Always prepend to ensure the requested Node version is first in PATH
let node_bin_dir = runtime.get_bin_prefix();
let new_path = format_path_prepended(node_bin_dir.as_path());
// 4. Build PATH with the limited core bin dir first (uses platform-specific separator)
let core_bin_dir = ensure_node_core_bin_prefix(&runtime.get_binary_path())?;
let new_path = format_path_prepended(core_bin_dir.as_path());

// 5. Execute command
let (cmd, args) = command.split_first().unwrap();
Expand Down
4 changes: 2 additions & 2 deletions crates/vite_global_cli/src/commands/env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,14 @@ async fn print_env(cwd: AbsolutePathBuf) -> Result<ExitStatus, Error> {
// Resolve the Node.js version for the current directory
let resolution = config::resolve_version(&cwd).await?;

// Get the node bin directory
// Get the limited core bin directory
let runtime = vite_js_runtime::download_runtime(
vite_js_runtime::JsRuntimeType::Node,
&resolution.version,
)
.await?;

let bin_dir = runtime.get_bin_prefix();
let bin_dir = runtime.ensure_core_bin_prefix()?;
let snippet = match detect_shell() {
Shell::NuShell => {
format!("$env.PATH = ($env.PATH | prepend \"{}\")", bin_dir.as_path().display())
Expand Down
12 changes: 8 additions & 4 deletions crates/vite_global_cli/src/commands/global/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
use owo_colors::OwoColorize;
use tokio::process::Command;
use uuid::Uuid;
use vite_js_runtime::NodeProvider;
use vite_js_runtime::{NodeProvider, ensure_node_core_bin_prefix};
use vite_path::{AbsolutePath, AbsolutePathBuf, current_dir};
use vite_shared::{format_path_prepended, output};

Expand Down Expand Up @@ -154,6 +154,10 @@ pub async fn install(
let node_bin_dir = runtime.get_bin_prefix();
let npm_path =
if cfg!(windows) { node_bin_dir.join("npm.cmd") } else { node_bin_dir.join("npm") };
let node_core_dir = match ensure_node_core_bin_prefix(&runtime.get_binary_path()) {
Ok(path) => path,
Err(error) => return Err((None, Error::RuntimeDownload(error))),
};

// 3. Install packages in parallel
let mut packages = IndexMap::<String, Package>::new();
Expand Down Expand Up @@ -205,7 +209,7 @@ pub async fn install(
installs.push(async {
(
package_name.clone(),
install_one(package_name, package.spec, &npm_path, &node_bin_dir).await,
install_one(package_name, package.spec, &npm_path, &node_core_dir).await,
)
});
}
Expand Down Expand Up @@ -527,7 +531,7 @@ async fn install_one(
package_name: &str,
package_spec: &str,
npm_path: &AbsolutePathBuf,
node_bin_dir: &AbsolutePathBuf,
node_core_dir: &AbsolutePathBuf,
) -> Result<(InstalledPackage, File), Error> {
// 1. Create an immutable install directory.
let install_id = new_install_id();
Expand All @@ -540,7 +544,7 @@ async fn install_one(
let output = Command::new(npm_path.as_path())
.args(["install", "-g", "--no-fund", &package_spec])
.env("npm_config_prefix", install_dir.as_path())
.env("PATH", format_path_prepended(node_bin_dir.as_path()))
.env("PATH", format_path_prepended(node_core_dir.as_path()))
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.kill_on_drop(true)
Expand Down
12 changes: 7 additions & 5 deletions crates/vite_global_cli/src/commands/global/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use futures::{StreamExt, stream::FuturesUnordered};
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
use tar::Archive;
use tokio::process::Command;
use vite_js_runtime::ensure_node_core_bin_prefix;
use vite_path::{AbsolutePathBuf, current_dir};
use vite_shared::format_path_prepended;

Expand All @@ -33,7 +34,7 @@ struct PackageVersion {

struct NpmRegistry {
npm_path: AbsolutePathBuf,
node_bin_dir: AbsolutePathBuf,
node_core_dir: AbsolutePathBuf,
}

impl NpmRegistry {
Expand All @@ -49,26 +50,27 @@ impl NpmRegistry {
let node_bin_dir = runtime.get_bin_prefix();
let npm_path =
if cfg!(windows) { node_bin_dir.join("npm.cmd") } else { node_bin_dir.join("npm") };
let node_core_dir = ensure_node_core_bin_prefix(&runtime.get_binary_path())?;

Ok(Self { npm_path, node_bin_dir })
Ok(Self { npm_path, node_core_dir })
}

async fn latest_package_version(&self, package_spec: &str) -> Result<String, Error> {
let output = npm_view(&self.npm_path, &self.node_bin_dir, package_spec, "version").await?;
let output = npm_view(&self.npm_path, &self.node_core_dir, package_spec, "version").await?;

parse_npm_view_version(&output)
}
}

async fn npm_view(
npm_path: &AbsolutePathBuf,
node_bin_dir: &AbsolutePathBuf,
node_core_dir: &AbsolutePathBuf,
package_spec: &str,
field: &str,
) -> Result<Vec<u8>, Error> {
let output = Command::new(npm_path.as_path())
.args(["view", package_spec, field, "--json"])
.env("PATH", format_path_prepended(node_bin_dir.as_path()))
.env("PATH", format_path_prepended(node_core_dir.as_path()))
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
Expand Down
4 changes: 2 additions & 2 deletions crates/vite_global_cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ pub async fn prepend_js_runtime_to_path_env(project_path: &AbsolutePath) -> Resu
executor.ensure_cli_runtime().await?
};

let node_bin_prefix = runtime.get_bin_prefix();
// Use dedupe_anywhere=true to check if node bin already exists anywhere in PATH
let node_bin_prefix = runtime.ensure_core_bin_prefix()?;
// Use dedupe_anywhere=true to check if the core bin already exists anywhere in PATH
let options = PrependOptions { dedupe_anywhere: true };
if prepend_to_path_env(&node_bin_prefix, options) {
tracing::debug!("Set PATH to include {:?}", node_bin_prefix);
Expand Down
12 changes: 9 additions & 3 deletions crates/vite_global_cli/src/commands/vpx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,15 @@ async fn execute_global_binary(bin: GlobalBinary, args: &[String], cwd: &Absolut
}
};

// Prepend Node.js bin dir to PATH
let node_bin_dir = node_path.parent().expect("Node has no parent directory");
let _ = prepend_to_path_env(node_bin_dir, PrependOptions::default());
// Prepend Node.js core bin dir to PATH
let node_core_dir = match vite_js_runtime::ensure_node_core_bin_prefix(&node_path) {
Ok(path) => path,
Err(e) => {
output::error(&format!("vpx: Failed to prepare Node.js core PATH: {e}"));
return 1;
}
};
let _ = prepend_to_path_env(&node_core_dir, PrependOptions::default());

// Prepend local node_modules/.bin dirs to PATH
prepend_node_modules_bin_to_path(cwd);
Expand Down
8 changes: 4 additions & 4 deletions crates/vite_global_cli/src/js_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ impl JsExecutor {
// Use project's runtime based on its devEngines.runtime configuration
let runtime = self.ensure_project_runtime(project_path).await?;
let node_binary = runtime.get_binary_path();
let bin_prefix = runtime.get_bin_prefix();
let bin_prefix = runtime.ensure_core_bin_prefix()?;
self.run_js_entry(project_path, &node_binary, &bin_prefix, args).await
}

Expand All @@ -243,7 +243,7 @@ impl JsExecutor {
) -> Result<Output, Error> {
let runtime = self.ensure_project_runtime(project_path).await?;
let node_binary = runtime.get_binary_path();
let bin_prefix = runtime.get_bin_prefix();
let bin_prefix = runtime.ensure_core_bin_prefix()?;
self.run_js_entry_output(project_path, &node_binary, &bin_prefix, args).await
}

Expand All @@ -258,7 +258,7 @@ impl JsExecutor {
) -> Result<ExitStatus, Error> {
let runtime = self.ensure_cli_runtime().await?;
let node_binary = runtime.get_binary_path();
let bin_prefix = runtime.get_bin_prefix();
let bin_prefix = runtime.ensure_core_bin_prefix()?;
let scripts_dir = self.get_scripts_dir()?;
let entry_point = scripts_dir.join("bin.js");

Expand All @@ -285,7 +285,7 @@ impl JsExecutor {
) -> Result<ExitStatus, Error> {
let runtime = self.ensure_cli_runtime().await?;
let node_binary = runtime.get_binary_path();
let bin_prefix = runtime.get_bin_prefix();
let bin_prefix = runtime.ensure_core_bin_prefix()?;
self.run_js_entry(project_path, &node_binary, &bin_prefix, args).await
}

Expand Down
11 changes: 9 additions & 2 deletions crates/vite_global_cli/src/shim/corepack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,16 @@ async fn resolve_corepack_invocation() -> Result<CorepackInvocation, i32> {
};
if let Some(corepack_path) = corepack_path {
// The bundled corepack sits in the same bin directory as node;
// prepend it so corepack's child processes see the same runtime.
// prepend the limited core bin so child processes see the same runtime.
if let Some(node_bin_dir) = corepack_path.parent() {
let _ = prepend_to_path_env(node_bin_dir, PrependOptions::default());
let node_path = if cfg!(windows) {
node_bin_dir.join("node.exe")
} else {
node_bin_dir.join("node")
};
if let Ok(node_core_dir) = vite_js_runtime::ensure_node_core_bin_prefix(&node_path) {
let _ = prepend_to_path_env(&node_core_dir, PrependOptions::default());
}
}
// Match the core-tool dispatch: nested core-tool shims pass through.
// SAFETY: Setting env vars at this point before exec/spawn is safe
Expand Down
45 changes: 29 additions & 16 deletions crates/vite_global_cli/src/shim/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use vite_install::package_manager::{
PackageManagerType, download_package_manager, package_manager_bin_path,
package_manager_install_dir, resolve_package_manager_from_package_json,
};
use vite_js_runtime::ensure_node_core_bin_prefix;
use vite_path::{AbsolutePath, AbsolutePathBuf, current_dir};
use vite_shared::{PrependOptions, env_vars, output, prepend_to_path_env};

Expand Down Expand Up @@ -716,15 +717,15 @@ async fn resolve_matching_package_manager_tool(

async fn prepend_js_child_process_path_env(
cwd: &AbsolutePath,
node_bin_dir: &AbsolutePath,
node_core_dir: &AbsolutePath,
) -> Result<(), Error> {
let _ = prepend_to_path_env(node_bin_dir, PrependOptions::default());
let _ = prepend_to_path_env(node_core_dir, PrependOptions::default());

let Some(npm_path) = resolve_matching_package_manager_tool(cwd, "npm").await? else {
return Ok(());
};
if let Some(pm_bin_dir) = npm_path.parent()
&& pm_bin_dir != node_bin_dir
&& pm_bin_dir != node_core_dir
{
let _ = prepend_to_path_env(pm_bin_dir, PrependOptions::default());
}
Expand Down Expand Up @@ -878,7 +879,14 @@ pub async fn dispatch(tool: &str, args: &[String]) -> i32 {
// version was selected from `packageManager`, put that PM bin dir first so
// nested invocations see the same PM version while recursion prevention is set.
let node_bin_dir = node_path.parent().expect("Node has no parent directory");
if let Err(e) = prepend_js_child_process_path_env(&cwd, node_bin_dir).await {
let node_core_dir = match ensure_node_core_bin_prefix(&node_path) {
Ok(path) => path,
Err(e) => {
eprintln!("vp: Failed to prepare Node.js core PATH: {e}");
return 1;
}
};
if let Err(e) = prepend_js_child_process_path_env(&cwd, &node_core_dir).await {
eprintln!("vp: Failed to resolve package manager for child process PATH: {e}");
return 1;
}
Expand Down Expand Up @@ -979,16 +987,21 @@ async fn dispatch_package_binary(tool: &str, args: &[String]) -> i32 {
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}"
);
let node_core_dir = match ensure_node_core_bin_prefix(&node_path) {
Ok(path) => path,
Err(e) => {
eprintln!("vp: Failed to prepare Node.js core PATH: {e}");
return 1;
}
};
if let Err(e) =
prepend_js_child_process_path_env(&cwd, &node_core_dir).await
{
eprintln!(
"vp: Failed to resolve package manager for child process \
PATH: {e}"
);
return 1;
}
}
Err(e) => {
Expand Down Expand Up @@ -1089,14 +1102,14 @@ pub(crate) async fn package_binary_invocation(
.map_err(|e| format!("Binary '{tool}' not found: {e}"))?;

// Prepare environment for recursive invocations
let node_bin_dir =
node_path.parent().ok_or_else(|| "Node has no parent directory".to_string())?;
let node_core_dir = ensure_node_core_bin_prefix(&node_path)
.map_err(|e| format!("Failed to prepare Node.js core PATH: {e}"))?;
if let Ok(cwd) = current_dir() {
prepend_js_child_process_path_env(&cwd, node_bin_dir).await.map_err(|e| {
prepend_js_child_process_path_env(&cwd, &node_core_dir).await.map_err(|e| {
format!("Failed to resolve package manager for child process PATH: {e}")
})?;
} else {
let _ = prepend_to_path_env(node_bin_dir, PrependOptions::default());
let _ = prepend_to_path_env(&node_core_dir, PrependOptions::default());
}

// JS binaries (determined at install time and stored in metadata) run
Expand Down
4 changes: 2 additions & 2 deletions crates/vite_js_runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,6 @@ pub use provider::{
pub use providers::{LtsInfo, NodeProvider, NodeVersionEntry};
pub use runtime::{
JsRuntime, JsRuntimeType, VersionResolution, VersionSource, download_runtime,
download_runtime_for_project, download_runtime_with_provider, is_valid_version,
normalize_version, read_package_json, resolve_node_version,
download_runtime_for_project, download_runtime_with_provider, ensure_node_core_bin_prefix,
is_valid_version, normalize_version, read_package_json, resolve_node_version,
};
Loading
Loading