From dc2efc369a0ee5412ac93a63318613e2f3851e0d Mon Sep 17 00:00:00 2001 From: sangwook Date: Wed, 15 Apr 2026 00:45:12 +0900 Subject: [PATCH 1/5] feat(cli): add top-level rebuild alias --- crates/vite_global_cli/src/main.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/crates/vite_global_cli/src/main.rs b/crates/vite_global_cli/src/main.rs index aa33495fcd..5bc370bd63 100644 --- a/crates/vite_global_cli/src/main.rs +++ b/crates/vite_global_cli/src/main.rs @@ -36,6 +36,7 @@ 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) -> Vec { @@ -50,6 +51,15 @@ fn normalize_args(args: Vec) -> Vec { normalized.extend(args[2..].iter().cloned()); normalized } + // `vp rebuild ...` → `vp pm rebuild ...` + Some("rebuild") => { + let mut normalized = Vec::with_capacity(args.len() + 1); + normalized.push(args[0].clone()); + normalized.push("pm".to_string()); + normalized.push("rebuild".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...]` @@ -434,6 +444,20 @@ 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 unknown_argument_detected_without_pass_as_value_hint() { let error = try_parse_args_from(["vp".to_string(), "--cache".to_string()]) From 94bbaa6175efa89110dad00f961c21b34a90b1e3 Mon Sep 17 00:00:00 2001 From: sangwook Date: Wed, 15 Apr 2026 11:59:45 +0900 Subject: [PATCH 2/5] docs(cli): add rebuild to help output and documentation URL Co-Authored-By: Claude Opus 4.6 --- crates/vite_global_cli/src/help.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/vite_global_cli/src/help.rs b/crates/vite_global_cli/src/help.rs index 55767b0d56..f0927a7d1e 100644 --- a/crates/vite_global_cli/src/help.rs +++ b/crates/vite_global_cli/src/help.rs @@ -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"), @@ -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"), ], ), From 964e758086460ed37551eb7936ef4cacfc5cf4c1 Mon Sep 17 00:00:00 2001 From: sangwook Date: Wed, 15 Apr 2026 12:00:51 +0900 Subject: [PATCH 3/5] docs: add rebuild section to install guide Co-Authored-By: Claude Opus 4.6 --- docs/guide/install.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/guide/install.md b/docs/guide/install.md index 374b21f8ca..87c782ca62 100644 --- a/docs/guide/install.md +++ b/docs/guide/install.md @@ -60,6 +60,7 @@ Vite+ provides all the familiar package management commands: - `vp list` shows installed packages - `vp why ` explains why a package is present - `vp info ` 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 ` runs a package binary without adding it to the project - `vp pm ` forwards a raw package-manager-specific command when you need behavior outside the normalized `vp` command set @@ -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 -- ` 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. From c0e791294a5646430793cfa59231c330c08d82b1 Mon Sep 17 00:00:00 2001 From: sangwook Date: Wed, 15 Apr 2026 21:52:20 +0900 Subject: [PATCH 4/5] fix(cli): support chained argument normalization - Refactor `normalize_args` to run in a loop, allowing multiple normalizations to be applied sequentially. - This fixes issues where commands like `vp help rebuild` or `vp help node` were not fully normalized to their target commands. - Update global CLI snapshot tests to reflect the new `rebuild` top-level command in help output. --- crates/vite_global_cli/src/main.rs | 107 +++++++++++------- .../cli-helper-message/snap.txt | 2 +- 2 files changed, 65 insertions(+), 44 deletions(-) diff --git a/crates/vite_global_cli/src/main.rs b/crates/vite_global_cli/src/main.rs index 5bc370bd63..54c58b2a1f 100644 --- a/crates/vite_global_cli/src/main.rs +++ b/crates/vite_global_cli/src/main.rs @@ -40,49 +40,56 @@ use crate::cli::{ /// - `vp help [command]` → `vp [command] --help` /// - `vp node [args...]` → `vp env exec node [args...]` fn normalize_args(args: Vec) -> Vec { - 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 rebuild ...` → `vp pm rebuild ...` - Some("rebuild") => { - let mut normalized = Vec::with_capacity(args.len() + 1); - normalized.push(args[0].clone()); - normalized.push("pm".to_string()); - normalized.push("rebuild".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; } } @@ -458,6 +465,20 @@ mod tests { 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()]) diff --git a/packages/cli/snap-tests-global/cli-helper-message/snap.txt b/packages/cli/snap-tests-global/cli-helper-message/snap.txt index b4f36cc96c..42ff9e0b12 100644 --- a/packages/cli/snap-tests-global/cli-helper-message/snap.txt +++ b/packages/cli/snap-tests-global/cli-helper-message/snap.txt @@ -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: @@ -441,4 +442,3 @@ Options: -h, --help Print help Documentation: https://viteplus.dev/guide/upgrade - From f29519312613494b9b818b3ff48f330b21dbb70e Mon Sep 17 00:00:00 2001 From: sangwook Date: Wed, 15 Apr 2026 23:48:59 +0900 Subject: [PATCH 5/5] test: update cli-helper-message snapshot --- packages/cli/snap-tests-global/cli-helper-message/snap.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cli/snap-tests-global/cli-helper-message/snap.txt b/packages/cli/snap-tests-global/cli-helper-message/snap.txt index 42ff9e0b12..b376b8dc1f 100644 --- a/packages/cli/snap-tests-global/cli-helper-message/snap.txt +++ b/packages/cli/snap-tests-global/cli-helper-message/snap.txt @@ -442,3 +442,4 @@ Options: -h, --help Print help Documentation: https://viteplus.dev/guide/upgrade +