Skip to content

Commit a5000aa

Browse files
authored
Merge branch 'main' into deps/upstream-update
2 parents ef60ba1 + 53d7be0 commit a5000aa

File tree

7 files changed

+123
-54
lines changed

7 files changed

+123
-54
lines changed

crates/vite_global_cli/src/help.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ fn documentation_url_for_command_path(command_path: &[&str]) -> Option<&'static
6565
["config"] | ["staged"] => Some("https://viteplus.dev/guide/commit-hooks"),
6666
[
6767
"install" | "add" | "remove" | "update" | "dedupe" | "outdated" | "list" | "ls" | "why"
68-
| "info" | "view" | "show" | "link" | "unlink" | "pm",
68+
| "info" | "view" | "show" | "link" | "unlink" | "rebuild" | "pm",
6969
..,
7070
] => Some("https://viteplus.dev/guide/install"),
7171
["dev"] => Some("https://viteplus.dev/guide/dev"),
@@ -477,6 +477,7 @@ pub fn top_level_help_doc() -> HelpDoc {
477477
row("info, view, show", "View package information from the registry"),
478478
row("link, ln", "Link packages for local development"),
479479
row("unlink", "Unlink packages"),
480+
row("rebuild", "Rebuild native modules"),
480481
row("pm", "Forward a command to the package manager"),
481482
],
482483
),

crates/vite_global_cli/src/main.rs

Lines changed: 79 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -36,43 +36,60 @@ use crate::cli::{
3636

3737
/// Normalize CLI arguments:
3838
/// - `vp list ...` / `vp ls ...` → `vp pm list ...`
39+
/// - `vp rebuild ...` → `vp pm rebuild ...`
3940
/// - `vp help [command]` → `vp [command] --help`
4041
/// - `vp node [args...]` → `vp env exec node [args...]`
4142
fn normalize_args(args: Vec<String>) -> Vec<String> {
42-
match args.get(1).map(String::as_str) {
43-
// `vp list ...` → `vp pm list ...`
44-
// `vp ls ...` → `vp pm list ...`
45-
Some("list" | "ls") => {
46-
let mut normalized = Vec::with_capacity(args.len() + 1);
47-
normalized.push(args[0].clone());
48-
normalized.push("pm".to_string());
49-
normalized.push("list".to_string());
50-
normalized.extend(args[2..].iter().cloned());
51-
normalized
52-
}
53-
// `vp help` alone -> show main help
54-
Some("help") if args.len() == 2 => vec![args[0].clone(), "--help".to_string()],
55-
// `vp help [command] [args...]` -> `vp [command] --help [args...]`
56-
Some("help") if args.len() > 2 => {
57-
let mut normalized = Vec::with_capacity(args.len());
58-
normalized.push(args[0].clone());
59-
normalized.push(args[2].clone());
60-
normalized.push("--help".to_string());
61-
normalized.extend(args[3..].iter().cloned());
62-
normalized
63-
}
64-
// `vp node [args...]` → `vp env exec node [args...]`
65-
Some("node") => {
66-
let mut normalized = Vec::with_capacity(args.len() + 2);
67-
normalized.push(args[0].clone());
68-
normalized.push("env".to_string());
69-
normalized.push("exec".to_string());
70-
normalized.push("node".to_string());
71-
normalized.extend(args[2..].iter().cloned());
72-
normalized
73-
}
74-
// No transformation needed
75-
_ => args,
43+
let mut normalized = args;
44+
loop {
45+
let next = match normalized.get(1).map(String::as_str) {
46+
// `vp list ...` → `vp pm list ...`
47+
// `vp ls ...` → `vp pm list ...`
48+
Some("list" | "ls") => {
49+
let mut next = Vec::with_capacity(normalized.len() + 1);
50+
next.push(normalized[0].clone());
51+
next.push("pm".to_string());
52+
next.push("list".to_string());
53+
next.extend(normalized[2..].iter().cloned());
54+
next
55+
}
56+
// `vp rebuild ...` → `vp pm rebuild ...`
57+
Some("rebuild") => {
58+
let mut next = Vec::with_capacity(normalized.len() + 1);
59+
next.push(normalized[0].clone());
60+
next.push("pm".to_string());
61+
next.push("rebuild".to_string());
62+
next.extend(normalized[2..].iter().cloned());
63+
next
64+
}
65+
// `vp help` alone -> show main help
66+
Some("help") if normalized.len() == 2 => {
67+
vec![normalized[0].clone(), "--help".to_string()]
68+
}
69+
// `vp help [command] [args...]` -> `vp [command] --help [args...]`
70+
Some("help") if normalized.len() > 2 => {
71+
let mut next = Vec::with_capacity(normalized.len());
72+
next.push(normalized[0].clone());
73+
next.push(normalized[2].clone());
74+
next.push("--help".to_string());
75+
next.extend(normalized[3..].iter().cloned());
76+
next
77+
}
78+
// `vp node [args...]` → `vp env exec node [args...]`
79+
Some("node") => {
80+
let mut next = Vec::with_capacity(normalized.len() + 2);
81+
next.push(normalized[0].clone());
82+
next.push("env".to_string());
83+
next.push("exec".to_string());
84+
next.push("node".to_string());
85+
next.extend(normalized[2..].iter().cloned());
86+
next
87+
}
88+
// No transformation needed
89+
_ => return normalized,
90+
};
91+
92+
normalized = next;
7693
}
7794
}
7895

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

454+
#[test]
455+
fn normalize_args_rewrites_bare_vp_rebuild() {
456+
let input = s(&["vp", "rebuild"]);
457+
let normalized = normalize_args(input);
458+
assert_eq!(normalized, s(&["vp", "pm", "rebuild"]));
459+
}
460+
461+
#[test]
462+
fn normalize_args_rewrites_vp_rebuild_with_args() {
463+
let input = s(&["vp", "rebuild", "--", "--update-binary"]);
464+
let normalized = normalize_args(input);
465+
assert_eq!(normalized, s(&["vp", "pm", "rebuild", "--", "--update-binary"]));
466+
}
467+
468+
#[test]
469+
fn normalize_args_rewrites_vp_help_rebuild() {
470+
let input = s(&["vp", "help", "rebuild"]);
471+
let normalized = normalize_args(input);
472+
assert_eq!(normalized, s(&["vp", "pm", "rebuild", "--help"]));
473+
}
474+
475+
#[test]
476+
fn normalize_args_rewrites_vp_help_node() {
477+
let input = s(&["vp", "help", "node"]);
478+
let normalized = normalize_args(input);
479+
assert_eq!(normalized, s(&["vp", "env", "exec", "node", "--help"]));
480+
}
481+
437482
#[test]
438483
fn unknown_argument_detected_without_pass_as_value_hint() {
439484
let error = try_parse_args_from(["vp".to_string(), "--cache".to_string()])

crates/vite_shared/src/tracing.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Tracing initialization for vite-plus
22
3-
use std::sync::OnceLock;
3+
use std::{str::FromStr, sync::OnceLock};
44

55
use tracing_subscriber::{
66
filter::{LevelFilter, Targets},
@@ -14,25 +14,28 @@ use crate::env_vars;
1414
/// Uses `OnceLock` to ensure tracing is only initialized once,
1515
/// even if called multiple times.
1616
///
17+
/// Only sets the global default subscriber when `VITE_LOG` is set.
18+
/// When unset, the global default slot is left free so that other
19+
/// subscribers (e.g., rolldown devtools) can claim it without panicking.
20+
///
1721
/// # Environment Variables
1822
/// - `VITE_LOG`: Controls log filtering (e.g., "debug", "vite_task=trace")
1923
pub fn init_tracing() {
2024
static TRACING: OnceLock<()> = OnceLock::new();
2125
TRACING.get_or_init(|| {
26+
let Ok(env_var) = std::env::var(env_vars::VITE_LOG) else {
27+
return;
28+
};
29+
2230
tracing_subscriber::registry()
2331
.with(
24-
std::env::var(env_vars::VITE_LOG)
25-
.map_or_else(
26-
|_| Targets::new(),
27-
|env_var| {
28-
use std::str::FromStr;
29-
Targets::from_str(&env_var).unwrap_or_default()
30-
},
31-
)
32+
Targets::from_str(&env_var)
33+
.unwrap_or_default()
3234
// disable brush-parser tracing
3335
.with_targets([("tokenize", LevelFilter::OFF), ("parse", LevelFilter::OFF)]),
3436
)
3537
.with(tracing_subscriber::fmt::layer())
36-
.init();
38+
.try_init()
39+
.ok();
3740
});
3841
}

docs/guide/install.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ Vite+ provides all the familiar package management commands:
6060
- `vp list` shows installed packages
6161
- `vp why <pkg>` explains why a package is present
6262
- `vp info <pkg>` shows registry metadata for a package
63+
- `vp rebuild` rebuilds native modules (e.g. after switching Node.js versions)
6364
- `vp link` and `vp unlink` manage local package links
6465
- `vp dlx <pkg>` runs a package binary without adding it to the project
6566
- `vp pm <command>` 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.
115116
- `vp why react` explains why `react` is installed
116117
- `vp info react` shows registry metadata such as versions and dist-tags
117118

119+
#### Rebuild
120+
121+
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.
122+
123+
- `vp rebuild` rebuilds all native modules
124+
- `vp rebuild -- <args>` passes extra arguments to the underlying package manager
125+
126+
```bash
127+
vp rebuild
128+
vp rebuild -- --update-binary
129+
```
130+
131+
`vp rebuild` is a shorthand for `vp pm rebuild`.
132+
118133
#### Advanced
119134

120135
Use these when you need lower-level package-manager behavior.

packages/cli/snap-tests-global/cli-helper-message/snap.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Manage Dependencies:
4141
info, view, show View package information from the registry
4242
link, ln Link packages for local development
4343
unlink Unlink packages
44+
rebuild Rebuild native modules
4445
pm Forward a command to the package manager
4546

4647
Maintain:

packages/prompts/src/__tests__/__snapshots__/render.spec.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ exports[`prompt renderers > renders multiselect with cursor marker plus checkbox
5252
Second line
5353
› ◼ Beta
5454
◻ Gamma
55+
Press space to select, enter to submit
5556
5657
"
5758
`;

packages/prompts/src/multi-select.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,15 @@ export const multiselect = <Value>(opts: MultiSelectOptions<Value>) => {
120120
);
121121
};
122122
const required = opts.required ?? true;
123+
const hint =
124+
' ' +
125+
color.reset(
126+
color.dim(
127+
`Press ${color.gray(color.bgWhite(color.inverse(' space ')))} to select, ${color.gray(
128+
color.bgWhite(color.inverse(' enter ')),
129+
)} to submit`,
130+
),
131+
);
123132

124133
return new MultiSelectPrompt({
125134
options: opts.options,
@@ -131,13 +140,7 @@ export const multiselect = <Value>(opts: MultiSelectOptions<Value>) => {
131140
cursorAt: opts.cursorAt,
132141
validate(selected: Value[] | undefined) {
133142
if (required && (selected === undefined || selected.length === 0)) {
134-
return `Please select at least one option.\n${color.reset(
135-
color.dim(
136-
`Press ${color.gray(color.bgWhite(color.inverse(' space ')))} to select, ${color.gray(
137-
color.bgWhite(color.inverse(' enter ')),
138-
)} to submit`,
139-
),
140-
)}`;
143+
return `Please select at least one option.\n${hint}`;
141144
}
142145
return undefined;
143146
},
@@ -221,7 +224,7 @@ export const multiselect = <Value>(opts: MultiSelectOptions<Value>) => {
221224
columnPadding: prefix.length,
222225
rowPadding: titleLineCount + footerLineCount,
223226
style: styleOption,
224-
}).join(`\n${prefix}`)}\n${footer}\n`;
227+
}).join(`\n${prefix}`)}\n${hint}\n${footer}\n`;
225228
}
226229
default: {
227230
const prefix = hasGuide ? `${color.blue(S_BAR)} ` : nestedPrefix;
@@ -236,7 +239,7 @@ export const multiselect = <Value>(opts: MultiSelectOptions<Value>) => {
236239
columnPadding: prefix.length,
237240
rowPadding: titleLineCount + footerLineCount,
238241
style: styleOption,
239-
}).join(`\n${prefix}`)}\n${hasGuide ? color.blue(S_BAR_END) : ''}\n`;
242+
}).join(`\n${prefix}`)}\n${hint}\n${hasGuide ? color.blue(S_BAR_END) : ''}\n`;
240243
}
241244
}
242245
},

0 commit comments

Comments
 (0)