diff --git a/crates/vite_command/src/lib.rs b/crates/vite_command/src/lib.rs index 64da37182f..855b46fa84 100644 --- a/crates/vite_command/src/lib.rs +++ b/crates/vite_command/src/lib.rs @@ -159,8 +159,17 @@ where { let cwd = cwd.as_ref(); let (program, prefix_args) = resolve_program(bin_name, envs, cwd)?; + let args: Vec = args.into_iter().map(|s| s.as_ref().to_owned()).collect(); + tracing::debug!( + target: "vite_command::spawn", + program = %program.as_path().display(), + prefix_args = ?prefix_args, + args = ?args, + cwd = %cwd.as_path().display(), + "spawn", + ); let mut cmd = build_command(&program, cwd); - cmd.args(&prefix_args).args(args).envs(envs); + cmd.args(&prefix_args).args(&args).envs(envs); let status = cmd.status().await?; Ok(status) } @@ -188,8 +197,16 @@ where S: AsRef, { let cwd = cwd.as_ref(); + let args: Vec = args.into_iter().map(|s| s.as_ref().to_owned()).collect(); + tracing::debug!( + target: "vite_command::spawn", + bin_name, + args = ?args, + cwd = %cwd.as_path().display(), + "spawn (fspy)", + ); let mut cmd = fspy::Command::new(bin_name); - cmd.args(args) + cmd.args(&args) // set system environment variables first .envs(std::env::vars_os()) // then set custom environment variables diff --git a/crates/vite_install/src/commands/rebuild.rs b/crates/vite_install/src/commands/rebuild.rs index b85725ef3b..7cdd3e91d9 100644 --- a/crates/vite_install/src/commands/rebuild.rs +++ b/crates/vite_install/src/commands/rebuild.rs @@ -10,8 +10,9 @@ use crate::package_manager::{ }; /// Options for the rebuild command. -#[derive(Debug)] +#[derive(Debug, Default)] pub struct RebuildCommandOptions<'a> { + pub packages: &'a [String], pub pass_through_args: Option<&'a [String]>, } @@ -69,10 +70,10 @@ impl PackageManager { } } - // Add pass-through args if let Some(pass_through_args) = options.pass_through_args { args.extend_from_slice(pass_through_args); } + args.extend_from_slice(options.packages); Some(ResolveCommandResult { bin_path: bin_name, args, envs }) } @@ -110,7 +111,7 @@ mod tests { #[test] fn test_npm_rebuild() { let pm = create_mock_package_manager(PackageManagerType::Npm, "11.0.0"); - let result = pm.resolve_rebuild_command(&RebuildCommandOptions { pass_through_args: None }); + let result = pm.resolve_rebuild_command(&RebuildCommandOptions::default()); assert!(result.is_some()); let result = result.unwrap(); assert_eq!(result.bin_path, "npm"); @@ -120,7 +121,7 @@ mod tests { #[test] fn test_pnpm_rebuild() { let pm = create_mock_package_manager(PackageManagerType::Pnpm, "10.0.0"); - let result = pm.resolve_rebuild_command(&RebuildCommandOptions { pass_through_args: None }); + let result = pm.resolve_rebuild_command(&RebuildCommandOptions::default()); assert!(result.is_some()); let result = result.unwrap(); assert_eq!(result.bin_path, "pnpm"); @@ -130,14 +131,54 @@ mod tests { #[test] fn test_yarn1_rebuild_not_supported() { let pm = create_mock_package_manager(PackageManagerType::Yarn, "1.22.0"); - let result = pm.resolve_rebuild_command(&RebuildCommandOptions { pass_through_args: None }); + let result = pm.resolve_rebuild_command(&RebuildCommandOptions::default()); assert!(result.is_none()); } #[test] fn test_yarn2_rebuild_not_supported() { let pm = create_mock_package_manager(PackageManagerType::Yarn, "4.0.0"); - let result = pm.resolve_rebuild_command(&RebuildCommandOptions { pass_through_args: None }); + let result = pm.resolve_rebuild_command(&RebuildCommandOptions::default()); assert!(result.is_none()); } + + #[test] + fn test_npm_rebuild_with_packages() { + let pm = create_mock_package_manager(PackageManagerType::Npm, "11.0.0"); + let packages = vec!["better-sqlite3".to_string(), "sharp".to_string()]; + let result = pm.resolve_rebuild_command(&RebuildCommandOptions { + packages: &packages, + ..Default::default() + }); + let result = result.unwrap(); + assert_eq!(result.bin_path, "npm"); + assert_eq!(result.args, vec!["rebuild", "better-sqlite3", "sharp"]); + } + + #[test] + fn test_pnpm_rebuild_with_packages() { + let pm = create_mock_package_manager(PackageManagerType::Pnpm, "10.0.0"); + let packages = vec!["better-sqlite3".to_string()]; + let result = pm.resolve_rebuild_command(&RebuildCommandOptions { + packages: &packages, + ..Default::default() + }); + let result = result.unwrap(); + assert_eq!(result.bin_path, "pnpm"); + assert_eq!(result.args, vec!["rebuild", "better-sqlite3"]); + } + + #[test] + fn test_pnpm_rebuild_with_packages_and_pass_through() { + let pm = create_mock_package_manager(PackageManagerType::Pnpm, "11.0.6"); + let packages = vec!["better-sqlite3".to_string()]; + let pass_through = vec!["--recursive".to_string()]; + let result = pm.resolve_rebuild_command(&RebuildCommandOptions { + packages: &packages, + pass_through_args: Some(&pass_through), + }); + let result = result.unwrap(); + assert_eq!(result.bin_path, "pnpm"); + assert_eq!(result.args, vec!["rebuild", "--recursive", "better-sqlite3"]); + } } diff --git a/crates/vite_pm_cli/src/cli.rs b/crates/vite_pm_cli/src/cli.rs index f0a6bd6573..80ee9a8402 100644 --- a/crates/vite_pm_cli/src/cli.rs +++ b/crates/vite_pm_cli/src/cli.rs @@ -860,6 +860,9 @@ pub enum PmCommands { /// Rebuild native modules #[command(visible_alias = "rb")] Rebuild { + /// Packages to rebuild (rebuilds all if omitted) + packages: Vec, + /// Additional arguments #[arg(last = true, allow_hyphen_values = true)] pass_through_args: Option>, diff --git a/crates/vite_pm_cli/src/handlers.rs b/crates/vite_pm_cli/src/handlers.rs index 72536460cf..0108e6aa51 100644 --- a/crates/vite_pm_cli/src/handlers.rs +++ b/crates/vite_pm_cli/src/handlers.rs @@ -452,8 +452,11 @@ pub async fn run_pm_subcommand( Ok(pm.run_search_command(&options, cwd).await?) } - PmCommands::Rebuild { pass_through_args } => { - let options = RebuildCommandOptions { pass_through_args: pass_through_args.as_deref() }; + PmCommands::Rebuild { packages, pass_through_args } => { + let options = RebuildCommandOptions { + packages: &packages, + pass_through_args: pass_through_args.as_deref(), + }; Ok(pm.run_rebuild_command(&options, cwd).await?) } diff --git a/docs/guide/install.md b/docs/guide/install.md index 87c782ca62..066f0a60a4 100644 --- a/docs/guide/install.md +++ b/docs/guide/install.md @@ -121,15 +121,19 @@ Use these when you need to understand the current state of dependencies. 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 ` rebuilds the listed packages only - `vp rebuild -- ` passes extra arguments to the underlying package manager ```bash vp rebuild +vp rebuild better-sqlite3 sharp vp rebuild -- --update-binary ``` `vp rebuild` is a shorthand for `vp pm rebuild`. +With pnpm v10+, bare `vp rebuild` only rebuilds packages whose build scripts are listed in `onlyBuiltDependencies` (or approved via `pnpm approve-builds`); name the package explicitly to force a rebuild that bypasses the approval gate. + #### Advanced Use these when you need lower-level package-manager behavior. diff --git a/packages/cli/snap-tests-global/command-rebuild-pnpm11/package.json b/packages/cli/snap-tests-global/command-rebuild-pnpm11/package.json new file mode 100644 index 0000000000..a22e22e3aa --- /dev/null +++ b/packages/cli/snap-tests-global/command-rebuild-pnpm11/package.json @@ -0,0 +1,9 @@ +{ + "name": "command-rebuild-pnpm11", + "version": "1.0.0", + "private": true, + "dependencies": { + "testnpm2": "1.0.0" + }, + "packageManager": "pnpm@11.0.6" +} diff --git a/packages/cli/snap-tests-global/command-rebuild-pnpm11/snap.txt b/packages/cli/snap-tests-global/command-rebuild-pnpm11/snap.txt new file mode 100644 index 0000000000..68ba728d8c --- /dev/null +++ b/packages/cli/snap-tests-global/command-rebuild-pnpm11/snap.txt @@ -0,0 +1,28 @@ +> vp rebuild --help # should show help with [PACKAGES]... positional +Usage: vp pm rebuild [PACKAGES]... [-- ...] + +Rebuild native modules + +Arguments: + [PACKAGES]... Packages to rebuild (rebuilds all if omitted) + [PASS_THROUGH_ARGS]... Additional arguments + +Options: + -h, --help Print help + +Documentation: https://viteplus.dev/guide/install + + +> vp install # set up node_modules +Packages: + ++ +Progress: resolved , reused , downloaded , added , done + +dependencies: ++ testnpm2 (1.0.1 is available) + +Done in ms using pnpm v + +> vp rebuild # bare rebuild, no args +> vp rebuild testnpm2 # should accept positional package name +> vp rebuild testnpm2 -- --recursive # package name + pass-through args \ No newline at end of file diff --git a/packages/cli/snap-tests-global/command-rebuild-pnpm11/steps.json b/packages/cli/snap-tests-global/command-rebuild-pnpm11/steps.json new file mode 100644 index 0000000000..b4040831b7 --- /dev/null +++ b/packages/cli/snap-tests-global/command-rebuild-pnpm11/steps.json @@ -0,0 +1,10 @@ +{ + "ignoredPlatforms": ["win32"], + "commands": [ + "vp rebuild --help # should show help with [PACKAGES]... positional", + "vp install # set up node_modules", + "vp rebuild # bare rebuild, no args", + "vp rebuild testnpm2 # should accept positional package name", + "vp rebuild testnpm2 -- --recursive # package name + pass-through args" + ] +}