Skip to content
Draft
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: 1 addition & 1 deletion crates/vite_global_cli/src/commands/env/doctor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const KNOWN_VERSION_MANAGERS: &[(&str, &str)] = &[
];

/// Tools that should have shims
const SHIM_TOOLS: &[&str] = &["node", "npm", "npx", "vpx"];
const SHIM_TOOLS: &[&str] = &["node", "npm", "npx", "vpx", "vpr"];

/// Column width for left-side keys in aligned output
const KEY_WIDTH: usize = 18;
Expand Down
4 changes: 2 additions & 2 deletions crates/vite_global_cli/src/commands/env/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use owo_colors::OwoColorize;
use super::config::{get_bin_dir, get_vite_plus_home};
use crate::{cli::Args, error::Error, help};

/// Tools to create shims for (node, npm, npx, vpx)
const SHIM_TOOLS: &[&str] = &["node", "npm", "npx", "vpx"];
/// Tools to create shims for (node, npm, npx, vpx, vpr)
const SHIM_TOOLS: &[&str] = &["node", "npm", "npx", "vpx", "vpr"];

fn accent_command(command: &str) -> String {
if help::should_style_help() {
Expand Down
3 changes: 2 additions & 1 deletion crates/vite_global_cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ pub mod version;
// Category D: Environment Management
pub mod env;

// Standalone binary command
// Standalone binary commands
pub mod vpr;
pub mod vpx;

// Self-Management
Expand Down
26 changes: 26 additions & 0 deletions crates/vite_global_cli/src/commands/vpr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//! `vpr` command implementation.
//!
//! Standalone shorthand for `vp run`. Executes tasks via the same
//! run-or-delegate logic: delegates to local vite-plus CLI when
//! vite-plus is a dependency, otherwise falls back to `<pm> run`.

use vite_path::AbsolutePath;
use vite_shared::output;

/// Main entry point for vpr execution.
///
/// Called from shim dispatch when `argv[0]` is `vpr`.
pub async fn execute_vpr(args: &[String], cwd: &AbsolutePath) -> i32 {
if crate::help::maybe_print_unified_delegate_help("run", args, true) {
return 0;
}

let cwd_buf = cwd.to_absolute_path_buf();
match super::run_or_delegate::execute(cwd_buf, args).await {
Ok(status) => status.code().unwrap_or(1),
Err(e) => {
output::error(&e.to_string());
1
}
}
}
2 changes: 1 addition & 1 deletion crates/vite_global_cli/src/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ pub fn top_level_help_doc() -> HelpDoc {
section_rows(
"Execute",
vec![
row("run", "Run tasks"),
row("run", "Run tasks (also available as standalone `vpr`)"),
row("exec", "Execute a command from local node_modules/.bin"),
row("dlx", "Execute a package binary without installing it as a dependency"),
row("cache", "Manage the task cache"),
Expand Down
12 changes: 12 additions & 0 deletions crates/vite_global_cli/src/shim/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,18 @@ pub async fn dispatch(tool: &str, args: &[String]) -> i32 {
return crate::commands::vpx::execute_vpx(args, &cwd).await;
}

// Handle vpr — standalone shorthand for `vp run`
if tool == "vpr" {
let cwd = match current_dir() {
Ok(path) => path,
Err(e) => {
eprintln!("vp: Failed to get current directory: {e}");
return 1;
}
};
return crate::commands::vpr::execute_vpr(args, &cwd).await;
}

// Check recursion prevention - if already in a shim context, passthrough directly
// Only applies to core tools (node/npm/npx) whose bin dir is prepended to PATH.
// Package binaries are always resolved via metadata lookup, so they can't loop.
Expand Down
22 changes: 22 additions & 0 deletions crates/vite_global_cli/src/shim/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ pub fn detect_shim_tool(argv0: &str) -> Option<String> {
if argv0_tool == "vpx" {
return Some("vpx".to_string());
}
if argv0_tool == "vpr" {
return Some("vpr".to_string());
}

// Fall back to argv[0] detection (Unix symlinks)
if is_shim_tool(&argv0_tool) { Some(argv0_tool) } else { None }
Expand Down Expand Up @@ -223,4 +226,23 @@ mod tests {
let result = detect_shim_tool("vpx.exe");
assert_eq!(result, Some("vpx".to_string()));
}

#[test]
fn test_detect_shim_tool_vpr() {
// vpr should be detected via the argv0 check, same pattern as vpx
// SAFETY: We're in a test
unsafe {
std::env::remove_var(SHIM_TOOL_ENV_VAR);
}
let result = detect_shim_tool("vpr");
assert_eq!(result, Some("vpr".to_string()));

// Also works with full path
let result = detect_shim_tool("/home/user/.vite-plus/bin/vpr");
assert_eq!(result, Some("vpr".to_string()));

// Also works with .exe extension (Windows)
let result = detect_shim_tool("vpr.exe");
assert_eq!(result, Some("vpr".to_string()));
}
}
2 changes: 1 addition & 1 deletion crates/vite_global_cli/src/tips/use_vpx_or_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ impl Tip for UseVpxOrRun {
}

fn message(&self) -> &'static str {
"Execute a package binary with `vpx <pkg[@version]>`, or a script with `vp run <script>`"
"Execute a package binary with `vpx <pkg[@version]>`, or a script with `vpr <script>` (or `vp run <script>`)"
}
}

Expand Down
4 changes: 4 additions & 0 deletions docs/guide/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

`vp run` runs `package.json` scripts and tasks defined in `vite.config.ts`. It works like `pnpm run`, with caching, dependency ordering, and workspace-aware execution built in.

::: tip
`vpr` is available as a standalone shorthand for `vp run`. All examples below work with both `vp run` and `vpr`.
:::

## Overview

Use `vp run` with existing `package.json` scripts:
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/snap-tests-global/cli-helper-message/snap.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Develop:
test Run tests

Execute:
run Run tasks
run Run tasks (also available as standalone `vpr`)
exec Execute a command from local node_modules/.bin
dlx Execute a package binary without installing it as a dependency
cache Manage the task cache
Expand Down
9 changes: 9 additions & 0 deletions packages/cli/snap-tests-global/command-vpr/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "command-vpr",
"version": "1.0.0",
"scripts": {
"hello": "echo hello from script",
"greet": "echo greet"
},
"packageManager": "pnpm@10.19.0"
}
51 changes: 51 additions & 0 deletions packages/cli/snap-tests-global/command-vpr/snap.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
> vpr -h # should show vp run help
VITE+ - The Unified Toolchain for the Web

Usage: vp run [OPTIONS] [TASK_SPECIFIER] [ADDITIONAL_ARGS]...

Run tasks.

Arguments:
[TASK_SPECIFIER] `packageName#taskName` or `taskName`. If omitted, lists all available tasks
[ADDITIONAL_ARGS]... Additional arguments to pass to the tasks

Options:
-r, --recursive Select all packages in the workspace
-t, --transitive Select the current package and its transitive dependencies
-w, --workspace-root Select the workspace root package
-F, --filter <FILTERS> Match packages by name, directory, or glob pattern
--ignore-depends-on Do not run dependencies specified in `dependsOn` fields
-v, --verbose Show full detailed summary after execution
--last-details Display the detailed summary of the last run
-h, --help Print help (see more with '--help')

Filter Patterns:
--filter <pattern> Select by package name (e.g. foo, @scope/*)
--filter ./<dir> Select packages under a directory
--filter {<dir>} Same as ./<dir>, but allows traversal suffixes
--filter <pattern>... Select package and its dependencies
--filter ...<pattern> Select package and its dependents
--filter <pattern>^... Select only the dependencies (exclude the package itself)
--filter !<pattern> Exclude packages matching the pattern

Documentation: https://viteplus.dev/guide/run


> vpr hello # should fall back to pnpm run when no vite-plus dependency

> command-vpr@<semver> hello <cwd>
> echo hello from script

hello from script

> vpr greet --arg1 value1 # should pass through args to pnpm run

> command-vpr@<semver> greet <cwd>
> echo greet --arg1 value1

greet --arg1 value1

[1]> vpr nonexistent # should show pnpm missing script error
 ERR_PNPM_NO_SCRIPT  Missing script: nonexistent

Command "nonexistent" not found.
8 changes: 8 additions & 0 deletions packages/cli/snap-tests-global/command-vpr/steps.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"commands": [
"vpr -h # should show vp run help",
"vpr hello # should fall back to pnpm run when no vite-plus dependency",
"vpr greet --arg1 value1 # should pass through args to pnpm run",
"vpr nonexistent # should show pnpm missing script error"
]
}
14 changes: 14 additions & 0 deletions rfcs/run-without-vite-plus-dependency.md
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,20 @@ fn test_yarn_run_script() {
}
```

## Standalone Shorthand: `vpr`

`vpr` is available as a standalone binary shorthand for `vp run`, following the same pattern as `vpx` (shorthand for `vp exec`). It is implemented as a shim symlink to the `vp` binary, detected via `argv[0]`, and dispatches to the same `run_or_delegate` logic:

```bash
# These are equivalent:
vpr dev
vp run dev

# Fallback behavior is identical:
vpr build # → <pm> run build (when no vite-plus dependency)
vpr -r build # → delegates to vite-plus task runner (when vite-plus is a dependency)
```

## Backward Compatibility

- **Projects with vite-plus**: No change in behavior. The `has_vite_plus_dependency` check passes, and delegation proceeds as before.
Expand Down
7 changes: 5 additions & 2 deletions rfcs/trampoline-exe-for-shims.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Implemented

## Summary

Replace Windows `.cmd` wrapper scripts with lightweight trampoline `.exe` binaries for all shim tools (`vp`, `node`, `npm`, `npx`, `vpx`, and globally installed package binaries). This eliminates the `Terminate batch job (Y/N)?` prompt that appears when users press Ctrl+C, providing the same clean signal behavior as direct `.exe` invocation.
Replace Windows `.cmd` wrapper scripts with lightweight trampoline `.exe` binaries for all shim tools (`vp`, `node`, `npm`, `npx`, `vpx`, `vpr`, and globally installed package binaries). This eliminates the `Terminate batch job (Y/N)?` prompt that appears when users press Ctrl+C, providing the same clean signal behavior as direct `.exe` invocation.

## Motivation

Expand Down Expand Up @@ -64,7 +64,9 @@ On Unix, shims are symlinks to the `vp` binary. The binary detects the tool name
├── vp → ../current/bin/vp (symlink)
├── node → ../current/bin/vp (symlink)
├── npm → ../current/bin/vp (symlink)
└── npx → ../current/bin/vp (symlink)
├── npx → ../current/bin/vp (symlink)
├── vpx → ../current/bin/vp (symlink)
└── vpr → ../current/bin/vp (symlink)
```

### Windows (Trampoline `.exe` Files)
Expand All @@ -76,6 +78,7 @@ On Unix, shims are symlinks to the `vp` binary. The binary detects the tool name
├── npm.exe # Trampoline → sets VITE_PLUS_SHIM_TOOL=npm, spawns vp.exe
├── npx.exe # Trampoline → sets VITE_PLUS_SHIM_TOOL=npx, spawns vp.exe
├── vpx.exe # Trampoline → sets VITE_PLUS_SHIM_TOOL=vpx, spawns vp.exe
├── vpr.exe # Trampoline → sets VITE_PLUS_SHIM_TOOL=vpr, spawns vp.exe
└── tsc.exe # Trampoline → sets VITE_PLUS_SHIM_TOOL=tsc, spawns vp.exe (package shim)
```

Expand Down
Loading