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
3 changes: 2 additions & 1 deletion crates/vite_global_cli/src/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ fn documentation_url_for_command_path(command_path: &[&str]) -> Option<&'static
["config"] | ["staged"] => Some("https://viteplus.dev/guide/commit-hooks"),
[
"install" | "add" | "remove" | "update" | "dedupe" | "outdated" | "list" | "ls" | "why"
| "info" | "view" | "show" | "link" | "unlink" | "pm",
| "info" | "view" | "show" | "link" | "unlink" | "rebuild" | "pm",
..,
] => Some("https://viteplus.dev/guide/install"),
["dev"] => Some("https://viteplus.dev/guide/dev"),
Expand Down Expand Up @@ -477,6 +477,7 @@ pub fn top_level_help_doc() -> HelpDoc {
row("info, view, show", "View package information from the registry"),
row("link, ln", "Link packages for local development"),
row("unlink", "Unlink packages"),
row("rebuild", "Rebuild native modules"),
row("pm", "Forward a command to the package manager"),
],
),
Expand Down
113 changes: 79 additions & 34 deletions crates/vite_global_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,43 +36,60 @@ use crate::cli::{

/// Normalize CLI arguments:
/// - `vp list ...` / `vp ls ...` → `vp pm list ...`
/// - `vp rebuild ...` → `vp pm rebuild ...`
/// - `vp help [command]` → `vp [command] --help`
/// - `vp node [args...]` → `vp env exec node [args...]`
fn normalize_args(args: Vec<String>) -> Vec<String> {
match args.get(1).map(String::as_str) {
// `vp list ...` → `vp pm list ...`
// `vp ls ...` → `vp pm list ...`
Some("list" | "ls") => {
let mut normalized = Vec::with_capacity(args.len() + 1);
normalized.push(args[0].clone());
normalized.push("pm".to_string());
normalized.push("list".to_string());
normalized.extend(args[2..].iter().cloned());
normalized
}
// `vp help` alone -> show main help
Some("help") if args.len() == 2 => vec![args[0].clone(), "--help".to_string()],
// `vp help [command] [args...]` -> `vp [command] --help [args...]`
Some("help") if args.len() > 2 => {
let mut normalized = Vec::with_capacity(args.len());
normalized.push(args[0].clone());
normalized.push(args[2].clone());
normalized.push("--help".to_string());
normalized.extend(args[3..].iter().cloned());
normalized
}
// `vp node [args...]` → `vp env exec node [args...]`
Some("node") => {
let mut normalized = Vec::with_capacity(args.len() + 2);
normalized.push(args[0].clone());
normalized.push("env".to_string());
normalized.push("exec".to_string());
normalized.push("node".to_string());
normalized.extend(args[2..].iter().cloned());
normalized
}
// No transformation needed
_ => args,
let mut normalized = args;
loop {
let next = match normalized.get(1).map(String::as_str) {
// `vp list ...` → `vp pm list ...`
// `vp ls ...` → `vp pm list ...`
Some("list" | "ls") => {
let mut next = Vec::with_capacity(normalized.len() + 1);
next.push(normalized[0].clone());
next.push("pm".to_string());
next.push("list".to_string());
next.extend(normalized[2..].iter().cloned());
next
}
// `vp rebuild ...` → `vp pm rebuild ...`
Some("rebuild") => {
let mut next = Vec::with_capacity(normalized.len() + 1);
next.push(normalized[0].clone());
next.push("pm".to_string());
next.push("rebuild".to_string());
next.extend(normalized[2..].iter().cloned());
next
}
// `vp help` alone -> show main help
Some("help") if normalized.len() == 2 => {
vec![normalized[0].clone(), "--help".to_string()]
}
// `vp help [command] [args...]` -> `vp [command] --help [args...]`
Some("help") if normalized.len() > 2 => {
let mut next = Vec::with_capacity(normalized.len());
next.push(normalized[0].clone());
next.push(normalized[2].clone());
next.push("--help".to_string());
next.extend(normalized[3..].iter().cloned());
next
}
// `vp node [args...]` → `vp env exec node [args...]`
Some("node") => {
let mut next = Vec::with_capacity(normalized.len() + 2);
next.push(normalized[0].clone());
next.push("env".to_string());
next.push("exec".to_string());
next.push("node".to_string());
next.extend(normalized[2..].iter().cloned());
next
}
// No transformation needed
_ => return normalized,
};

normalized = next;
}
}

Expand Down Expand Up @@ -434,6 +451,34 @@ mod tests {
assert_eq!(normalized, s(&["vp", "env", "exec", "node"]));
}

#[test]
fn normalize_args_rewrites_bare_vp_rebuild() {
let input = s(&["vp", "rebuild"]);
let normalized = normalize_args(input);
assert_eq!(normalized, s(&["vp", "pm", "rebuild"]));
}

#[test]
fn normalize_args_rewrites_vp_rebuild_with_args() {
let input = s(&["vp", "rebuild", "--", "--update-binary"]);
let normalized = normalize_args(input);
assert_eq!(normalized, s(&["vp", "pm", "rebuild", "--", "--update-binary"]));
}

#[test]
fn normalize_args_rewrites_vp_help_rebuild() {
let input = s(&["vp", "help", "rebuild"]);
let normalized = normalize_args(input);
assert_eq!(normalized, s(&["vp", "pm", "rebuild", "--help"]));
}

#[test]
fn normalize_args_rewrites_vp_help_node() {
let input = s(&["vp", "help", "node"]);
let normalized = normalize_args(input);
assert_eq!(normalized, s(&["vp", "env", "exec", "node", "--help"]));
}

#[test]
fn unknown_argument_detected_without_pass_as_value_hint() {
let error = try_parse_args_from(["vp".to_string(), "--cache".to_string()])
Expand Down
15 changes: 15 additions & 0 deletions docs/guide/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Vite+ provides all the familiar package management commands:
- `vp list` shows installed packages
- `vp why <pkg>` explains why a package is present
- `vp info <pkg>` shows registry metadata for a package
- `vp rebuild` rebuilds native modules (e.g. after switching Node.js versions)
- `vp link` and `vp unlink` manage local package links
- `vp dlx <pkg>` runs a package binary without adding it to the project
- `vp pm <command>` forwards a raw package-manager-specific command when you need behavior outside the normalized `vp` command set
Expand Down Expand Up @@ -115,6 +116,20 @@ Use these when you need to understand the current state of dependencies.
- `vp why react` explains why `react` is installed
- `vp info react` shows registry metadata such as versions and dist-tags

#### Rebuild

Use `vp rebuild` when native modules need to be recompiled, for example after switching Node.js versions or when a C/C++ addon fails to load.

- `vp rebuild` rebuilds all native modules
- `vp rebuild -- <args>` passes extra arguments to the underlying package manager

```bash
vp rebuild
vp rebuild -- --update-binary
```

`vp rebuild` is a shorthand for `vp pm rebuild`.

#### Advanced

Use these when you need lower-level package-manager behavior.
Expand Down
1 change: 1 addition & 0 deletions packages/cli/snap-tests-global/cli-helper-message/snap.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Manage Dependencies:
info, view, show View package information from the registry
link, ln Link packages for local development
unlink Unlink packages
rebuild Rebuild native modules
pm Forward a command to the package manager

Maintain:
Expand Down
Loading