Skip to content

Commit 45aacdd

Browse files
committed
fix: use CLI runtime for vp --version to avoid writing .node-version
1 parent 311d71b commit 45aacdd

5 files changed

Lines changed: 60 additions & 3 deletions

File tree

crates/vite_global_cli/src/commands/version.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ use std::process::ExitStatus;
44

55
use vite_path::AbsolutePathBuf;
66

7-
use crate::error::Error;
7+
use crate::{error::Error, js_executor::JsExecutor};
88

99
/// Execute the `--version` command by delegating to local or global vite-plus.
10+
///
11+
/// Uses the CLI's own runtime instead of the project's runtime to avoid
12+
/// side effects (e.g., writing `.node-version` in the caller's directory).
1013
pub async fn execute(cwd: AbsolutePathBuf) -> Result<ExitStatus, Error> {
1114
// Pass the Rust binary's version to JS so it can display the correct global version,
1215
// even when delegation resolves to a local node_modules copy.
@@ -16,7 +19,8 @@ pub async fn execute(cwd: AbsolutePathBuf) -> Result<ExitStatus, Error> {
1619
env!("CARGO_PKG_VERSION"),
1720
);
1821
}
19-
super::delegate::execute(cwd, "--version", &[]).await
22+
let mut executor = JsExecutor::new(None);
23+
executor.delegate_with_cli_runtime(&cwd, &["--version".to_string()]).await
2024
}
2125

2226
#[cfg(test)]

crates/vite_global_cli/src/js_executor.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ impl JsExecutor {
163163
/// If found, runs the local `dist/bin.js` directly. Otherwise, falls back
164164
/// to the global installation's `dist/bin.js`.
165165
///
166+
/// Uses the project's runtime (from its `devEngines.runtime` configuration).
167+
/// This may write a `.node-version` file if the project has no version source.
168+
/// For side-effect-free commands like `--version`, use [`delegate_with_cli_runtime`] instead.
169+
///
166170
/// # Arguments
167171
/// * `project_path` - Path to the project directory
168172
/// * `args` - Arguments to pass to the local CLI
@@ -175,7 +179,36 @@ impl JsExecutor {
175179
let runtime = self.ensure_project_runtime(project_path).await?;
176180
let node_binary = runtime.get_binary_path();
177181
let bin_prefix = runtime.get_bin_prefix();
182+
self.run_js_entry(project_path, &node_binary, &bin_prefix, args).await
183+
}
178184

185+
/// Delegate to local or global vite-plus CLI using the CLI's own runtime.
186+
///
187+
/// Like [`delegate_to_local_cli`], but uses the CLI's bundled runtime
188+
/// (from its own `devEngines.runtime` in `package.json`) instead of the
189+
/// project's runtime. This avoids side effects like writing `.node-version`
190+
/// when no version source exists in the project directory.
191+
///
192+
/// Use this for read-only / side-effect-free commands like `--version`.
193+
pub async fn delegate_with_cli_runtime(
194+
&mut self,
195+
project_path: &AbsolutePath,
196+
args: &[String],
197+
) -> Result<ExitStatus, Error> {
198+
let runtime = self.ensure_cli_runtime().await?;
199+
let node_binary = runtime.get_binary_path();
200+
let bin_prefix = runtime.get_bin_prefix();
201+
self.run_js_entry(project_path, &node_binary, &bin_prefix, args).await
202+
}
203+
204+
/// Run a JS entry point with the given runtime, resolving local vite-plus first.
205+
async fn run_js_entry(
206+
&self,
207+
project_path: &AbsolutePath,
208+
node_binary: &AbsolutePath,
209+
bin_prefix: &AbsolutePath,
210+
args: &[String],
211+
) -> Result<ExitStatus, Error> {
179212
// Try to resolve vite-plus from the project directory using oxc_resolver
180213
let entry_point = Self::resolve_local_vite_plus(project_path).unwrap_or_else(|| {
181214
// Fall back to the global installation's bin.js
@@ -185,7 +218,7 @@ impl JsExecutor {
185218

186219
tracing::debug!("Delegating to CLI via JS entry point: {:?} {:?}", entry_point, args);
187220

188-
let mut cmd = Self::create_js_command(&node_binary, &bin_prefix);
221+
let mut cmd = Self::create_js_command(node_binary, bin_prefix);
189222
cmd.arg(entry_point.as_path()).args(args).current_dir(project_path.as_path());
190223

191224
let status = cmd.status().await?;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "command-version-no-side-effects",
3+
"version": "1.0.0"
4+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
> vp --version # should print version
2+
VITE+ - The Unified Toolchain for the Web
3+
4+
PACKAGE VERSIONS:
5+
Global vite-plus: v<semver>
6+
Local vite-plus: Not found
7+
8+
> test -f .node-version && echo 'FAIL: .node-version was created' || echo 'OK: no .node-version created'
9+
OK: no .node-version created
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"ignoredPlatforms": ["win32"],
3+
"commands": [
4+
"vp --version # should print version",
5+
"test -f .node-version && echo 'FAIL: .node-version was created' || echo 'OK: no .node-version created'"
6+
]
7+
}

0 commit comments

Comments
 (0)