From 24c732230b2d803279fd9fc4d48acfdceebfc17e Mon Sep 17 00:00:00 2001 From: MK Date: Thu, 25 Dec 2025 21:35:18 +0800 Subject: [PATCH 1/4] feat(cli): add vite optimize and preview subcommands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add two new Vite CLI subcommands that forward arguments to the underlying Vite CLI: - `vite optimize`: Pre-bundle dependencies (with --force option) - `vite preview`: Preview production build (with --port, --host, etc.) Both commands follow the same pattern as existing `vite dev` and `vite build` commands. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- packages/cli/binding/src/cli.rs | 69 +++++++++++++++++++ packages/cli/binding/src/lib.rs | 5 +- .../cli/snap-tests/command-helper/snap.txt | 66 +++++++++++++++--- .../cli/snap-tests/command-helper/steps.json | 4 +- .../snap-tests/command-optimize/package.json | 2 + .../cli/snap-tests/command-optimize/snap.txt | 4 ++ .../snap-tests/command-optimize/steps.json | 9 +++ .../snap-tests/command-preview/package.json | 2 + .../cli/snap-tests/command-preview/snap.txt | 2 + .../cli/snap-tests/command-preview/steps.json | 9 +++ 10 files changed, 159 insertions(+), 13 deletions(-) create mode 100644 packages/cli/snap-tests/command-optimize/package.json create mode 100644 packages/cli/snap-tests/command-optimize/snap.txt create mode 100644 packages/cli/snap-tests/command-optimize/steps.json create mode 100644 packages/cli/snap-tests/command-preview/package.json create mode 100644 packages/cli/snap-tests/command-preview/snap.txt create mode 100644 packages/cli/snap-tests/command-preview/steps.json diff --git a/packages/cli/binding/src/cli.rs b/packages/cli/binding/src/cli.rs index d9a9a1c459..76c12388d7 100644 --- a/packages/cli/binding/src/cli.rs +++ b/packages/cli/binding/src/cli.rs @@ -108,6 +108,18 @@ pub enum Commands { /// Arguments to pass to vite dev args: Vec, }, + /// Pre-bundle dependencies + Optimize { + #[arg(allow_hyphen_values = true, trailing_var_arg = true)] + /// Arguments to pass to vite optimize + args: Vec, + }, + /// Preview production build + Preview { + #[arg(allow_hyphen_values = true, trailing_var_arg = true)] + /// Arguments to pass to vite preview + args: Vec, + }, /// Build documentation Doc { #[arg(allow_hyphen_values = true, trailing_var_arg = true)] @@ -431,6 +443,20 @@ pub async fn main< workspace.unload().await?; summary } + Commands::Optimize { args } => { + let workspace = Workspace::partial_load(cwd)?; + let vite_fn = options.map(|o| o.vite).expect("optimize command requires CliOptions"); + let summary = vite_cmd("optimize", vite_fn, &workspace, args).await?; + workspace.unload().await?; + summary + } + Commands::Preview { args } => { + let workspace = Workspace::partial_load(cwd)?; + let vite_fn = options.map(|o| o.vite).expect("preview command requires CliOptions"); + let summary = vite_cmd("preview", vite_fn, &workspace, args).await?; + workspace.unload().await?; + summary + } Commands::Doc { args } => { let workspace = Workspace::partial_load(cwd)?; let doc_fn = options.map(|o| o.doc).expect("doc command requires CliOptions"); @@ -941,6 +967,49 @@ mod tests { } } + #[test] + fn test_args_optimize_command() { + let args = Args::try_parse_from(["vite-plus", "optimize"]).unwrap(); + assert_eq!(args.task, None); + assert!(args.task_args.is_empty()); + assert!(matches!(args.commands, Commands::Optimize { .. })); + assert!(!args.debug); + } + + #[test] + fn test_args_optimize_command_with_args() { + let args = Args::try_parse_from(["vite-plus", "optimize", "--force"]).unwrap(); + assert_eq!(args.task, None); + assert!(args.task_args.is_empty()); + if let Commands::Optimize { args } = &args.commands { + assert_eq!(args, &vec!["--force".to_string()]); + } else { + panic!("Expected Optimize command"); + } + } + + #[test] + fn test_args_preview_command() { + let args = Args::try_parse_from(["vite-plus", "preview"]).unwrap(); + assert_eq!(args.task, None); + assert!(args.task_args.is_empty()); + assert!(matches!(args.commands, Commands::Preview { .. })); + assert!(!args.debug); + } + + #[test] + fn test_args_preview_command_with_args() { + let args = + Args::try_parse_from(["vite-plus", "preview", "--port", "3000", "--host"]).unwrap(); + assert_eq!(args.task, None); + assert!(args.task_args.is_empty()); + if let Commands::Preview { args } = &args.commands { + assert_eq!(args, &vec!["--port".to_string(), "3000".to_string(), "--host".to_string()]); + } else { + panic!("Expected Preview command"); + } + } + #[test] fn test_args_complex_task_args() { let args = Args::try_parse_from([ diff --git a/packages/cli/binding/src/lib.rs b/packages/cli/binding/src/lib.rs index b7a8b92d92..5b2e309773 100644 --- a/packages/cli/binding/src/lib.rs +++ b/packages/cli/binding/src/lib.rs @@ -80,7 +80,8 @@ impl From for ResolveCommandResult { } } -static BUILTIN_COMMANDS: &[&str] = &["lint", "fmt", "build", "test", "doc", "lib"]; +static BUILTIN_COMMANDS: &[&str] = + &["lint", "fmt", "build", "test", "doc", "lib", "optimize", "preview"]; /// Main entry point for the CLI, called from JavaScript. /// @@ -284,6 +285,8 @@ fn parse_args() -> Args { "test" => Commands::Test { args: forwarded_args }, "doc" => Commands::Doc { args: forwarded_args }, "lib" => Commands::Lib { args: forwarded_args }, + "optimize" => Commands::Optimize { args: forwarded_args }, + "preview" => Commands::Preview { args: forwarded_args }, _ => unreachable!(), }, debug: false, diff --git a/packages/cli/snap-tests/command-helper/snap.txt b/packages/cli/snap-tests/command-helper/snap.txt index 6113b10259..b876f78274 100644 --- a/packages/cli/snap-tests/command-helper/snap.txt +++ b/packages/cli/snap-tests/command-helper/snap.txt @@ -2,17 +2,19 @@ Usage: vite [OPTIONS] [TASK] [-- ...] Commands: - run Run tasks - lint Lint code - fmt Format code - build Build application - test Run test - lib Build library - dev Run development server - doc Build documentation - cache Manage the task cache - install Install command. It will be passed to the package manager's install command currently - help Print this message or the help of the given subcommand(s) + run Run tasks + lint Lint code + fmt Format code + build Build application + test Run test + lib Build library + dev Run development server + optimize Pre-bundle dependencies + preview Preview production build + doc Build documentation + cache Manage the task cache + install Install command. It will be passed to the package manager's install command currently + help Print this message or the help of the given subcommand(s) Arguments: [TASK] @@ -333,3 +335,45 @@ Options: --experimental Experimental features.. Use '--help --experimental' for more info. -h, --help Display this message + +> vite optimize -h # optimize help message +vite/ + +Usage: + $ vite optimize [root] + +Options: + --force [boolean] force the optimizer to ignore the cache and re-bundle + -c, --config [string] use specified config file + --base [string] public base path (default: /) + -l, --logLevel [string] info | warn | error | silent + --clearScreen [boolean] allow/disable clear screen when logging + --configLoader [string] use 'bundle' to bundle the config with Rolldown, or 'runner' (experimental) to process it on the fly, or 'native' (experimental) to load using the native runtime (default: bundle) + -d, --debug [feat] [string | boolean] show debug logs + -f, --filter [string] filter debug logs + -m, --mode [string] set env mode + -h, --help Display this message + + +> vite preview -h # preview help message +vite/ + +Usage: + $ vite preview [root] + +Options: + --host [host] [string] specify hostname + --port [number] specify port + --strictPort [boolean] exit if specified port is already in use + --open [path] [boolean | string] open browser on startup + --outDir [string] output directory (default: dist) + -c, --config [string] use specified config file + --base [string] public base path (default: /) + -l, --logLevel [string] info | warn | error | silent + --clearScreen [boolean] allow/disable clear screen when logging + --configLoader [string] use 'bundle' to bundle the config with Rolldown, or 'runner' (experimental) to process it on the fly, or 'native' (experimental) to load using the native runtime (default: bundle) + -d, --debug [feat] [string | boolean] show debug logs + -f, --filter [string] filter debug logs + -m, --mode [string] set env mode + -h, --help Display this message + diff --git a/packages/cli/snap-tests/command-helper/steps.json b/packages/cli/snap-tests/command-helper/steps.json index 706f525726..d718292080 100644 --- a/packages/cli/snap-tests/command-helper/steps.json +++ b/packages/cli/snap-tests/command-helper/steps.json @@ -9,6 +9,8 @@ "vite fmt -h # fmt help message", "vite lint -h # lint help message", "vite build -h # build help message", - "vite test -h # test help message" + "vite test -h # test help message", + "vite optimize -h # optimize help message", + "vite preview -h # preview help message" ] } diff --git a/packages/cli/snap-tests/command-optimize/package.json b/packages/cli/snap-tests/command-optimize/package.json new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/packages/cli/snap-tests/command-optimize/package.json @@ -0,0 +1,2 @@ +{ +} diff --git a/packages/cli/snap-tests/command-optimize/snap.txt b/packages/cli/snap-tests/command-optimize/snap.txt new file mode 100644 index 0000000000..84b2eb9024 --- /dev/null +++ b/packages/cli/snap-tests/command-optimize/snap.txt @@ -0,0 +1,4 @@ +[timeout]> vite optimize --force 2>&1 | head -3 # run optimize with force flag +manually calling optimizeDeps is deprecated. This is done automatically and does not need to be called manually. +9:32:42 PM [vite] (client) Forced re-optimization of dependencies +Optimizing dependencies: diff --git a/packages/cli/snap-tests/command-optimize/steps.json b/packages/cli/snap-tests/command-optimize/steps.json new file mode 100644 index 0000000000..2f52ee3688 --- /dev/null +++ b/packages/cli/snap-tests/command-optimize/steps.json @@ -0,0 +1,9 @@ +{ + "ignoredPlatforms": ["win32"], + "env": { + "VITE_DISABLE_AUTO_INSTALL": "1" + }, + "commands": [ + "vite optimize --force 2>&1 | head -3 # run optimize with force flag" + ] +} diff --git a/packages/cli/snap-tests/command-preview/package.json b/packages/cli/snap-tests/command-preview/package.json new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/packages/cli/snap-tests/command-preview/package.json @@ -0,0 +1,2 @@ +{ +} diff --git a/packages/cli/snap-tests/command-preview/snap.txt b/packages/cli/snap-tests/command-preview/snap.txt new file mode 100644 index 0000000000..a555b89040 --- /dev/null +++ b/packages/cli/snap-tests/command-preview/snap.txt @@ -0,0 +1,2 @@ +> vite preview --port 12312312312 2>&1 | grep RangeError # intentionally use an invalid port (exceeds 0-65535) to trigger RangeError +RangeError [ERR_SOCKET_BAD_PORT]: options.port should be >= 0 and < 65536. Received type number (12312312312). diff --git a/packages/cli/snap-tests/command-preview/steps.json b/packages/cli/snap-tests/command-preview/steps.json new file mode 100644 index 0000000000..b098bb0a85 --- /dev/null +++ b/packages/cli/snap-tests/command-preview/steps.json @@ -0,0 +1,9 @@ +{ + "ignoredPlatforms": ["win32"], + "env": { + "VITE_DISABLE_AUTO_INSTALL": "1" + }, + "commands": [ + "vite preview --port 12312312312 2>&1 | grep RangeError # intentionally use an invalid port (exceeds 0-65535) to trigger RangeError" + ] +} From f7e7a9426726c49ab2fb158c553da00744f82e32 Mon Sep 17 00:00:00 2001 From: MK Date: Thu, 25 Dec 2025 21:39:57 +0800 Subject: [PATCH 2/4] feat(global): forward optimize and preview commands to local CLI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add optimize and preview to LOCAL_CLI_COMMANDS so they are properly forwarded to the local CLI instead of being handled by the global Rust binary. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- packages/global/src/index.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/global/src/index.ts b/packages/global/src/index.ts index 7650aeada5..e90b3a38b5 100644 --- a/packages/global/src/index.ts +++ b/packages/global/src/index.ts @@ -1,7 +1,19 @@ // Parse command line arguments to intercept 'new', 'gen', and 'migration' commands const args = process.argv.slice(2); -const LOCAL_CLI_COMMANDS = ['dev', 'build', 'test', 'lint', 'fmt', 'format', 'lib', 'doc', 'run']; +const LOCAL_CLI_COMMANDS = [ + 'dev', + 'build', + 'test', + 'lint', + 'fmt', + 'format', + 'lib', + 'doc', + 'run', + 'optimize', + 'preview', +]; const command = args[0]; From 0aca3281817ee1de62faa8f26e2cafafb5e8232c Mon Sep 17 00:00:00 2001 From: MK Date: Thu, 25 Dec 2025 21:45:42 +0800 Subject: [PATCH 3/4] refactor(cli): remove deprecated vite optimize command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vite optimize command is deprecated as dependency pre-bundling now runs automatically. Only keep the vite preview command. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- packages/cli/binding/src/cli.rs | 34 -------------- packages/cli/binding/src/lib.rs | 4 +- .../cli/snap-tests/command-helper/snap.txt | 44 +++++-------------- .../cli/snap-tests/command-helper/steps.json | 1 - .../snap-tests/command-optimize/package.json | 2 - .../cli/snap-tests/command-optimize/snap.txt | 4 -- .../snap-tests/command-optimize/steps.json | 9 ---- packages/global/src/index.ts | 1 - 8 files changed, 13 insertions(+), 86 deletions(-) delete mode 100644 packages/cli/snap-tests/command-optimize/package.json delete mode 100644 packages/cli/snap-tests/command-optimize/snap.txt delete mode 100644 packages/cli/snap-tests/command-optimize/steps.json diff --git a/packages/cli/binding/src/cli.rs b/packages/cli/binding/src/cli.rs index 76c12388d7..d3a7832f95 100644 --- a/packages/cli/binding/src/cli.rs +++ b/packages/cli/binding/src/cli.rs @@ -108,12 +108,6 @@ pub enum Commands { /// Arguments to pass to vite dev args: Vec, }, - /// Pre-bundle dependencies - Optimize { - #[arg(allow_hyphen_values = true, trailing_var_arg = true)] - /// Arguments to pass to vite optimize - args: Vec, - }, /// Preview production build Preview { #[arg(allow_hyphen_values = true, trailing_var_arg = true)] @@ -443,13 +437,6 @@ pub async fn main< workspace.unload().await?; summary } - Commands::Optimize { args } => { - let workspace = Workspace::partial_load(cwd)?; - let vite_fn = options.map(|o| o.vite).expect("optimize command requires CliOptions"); - let summary = vite_cmd("optimize", vite_fn, &workspace, args).await?; - workspace.unload().await?; - summary - } Commands::Preview { args } => { let workspace = Workspace::partial_load(cwd)?; let vite_fn = options.map(|o| o.vite).expect("preview command requires CliOptions"); @@ -967,27 +954,6 @@ mod tests { } } - #[test] - fn test_args_optimize_command() { - let args = Args::try_parse_from(["vite-plus", "optimize"]).unwrap(); - assert_eq!(args.task, None); - assert!(args.task_args.is_empty()); - assert!(matches!(args.commands, Commands::Optimize { .. })); - assert!(!args.debug); - } - - #[test] - fn test_args_optimize_command_with_args() { - let args = Args::try_parse_from(["vite-plus", "optimize", "--force"]).unwrap(); - assert_eq!(args.task, None); - assert!(args.task_args.is_empty()); - if let Commands::Optimize { args } = &args.commands { - assert_eq!(args, &vec!["--force".to_string()]); - } else { - panic!("Expected Optimize command"); - } - } - #[test] fn test_args_preview_command() { let args = Args::try_parse_from(["vite-plus", "preview"]).unwrap(); diff --git a/packages/cli/binding/src/lib.rs b/packages/cli/binding/src/lib.rs index 5b2e309773..d19b5b9fcb 100644 --- a/packages/cli/binding/src/lib.rs +++ b/packages/cli/binding/src/lib.rs @@ -80,8 +80,7 @@ impl From for ResolveCommandResult { } } -static BUILTIN_COMMANDS: &[&str] = - &["lint", "fmt", "build", "test", "doc", "lib", "optimize", "preview"]; +static BUILTIN_COMMANDS: &[&str] = &["lint", "fmt", "build", "test", "doc", "lib", "preview"]; /// Main entry point for the CLI, called from JavaScript. /// @@ -285,7 +284,6 @@ fn parse_args() -> Args { "test" => Commands::Test { args: forwarded_args }, "doc" => Commands::Doc { args: forwarded_args }, "lib" => Commands::Lib { args: forwarded_args }, - "optimize" => Commands::Optimize { args: forwarded_args }, "preview" => Commands::Preview { args: forwarded_args }, _ => unreachable!(), }, diff --git a/packages/cli/snap-tests/command-helper/snap.txt b/packages/cli/snap-tests/command-helper/snap.txt index b876f78274..ca0974da1f 100644 --- a/packages/cli/snap-tests/command-helper/snap.txt +++ b/packages/cli/snap-tests/command-helper/snap.txt @@ -2,19 +2,18 @@ Usage: vite [OPTIONS] [TASK] [-- ...] Commands: - run Run tasks - lint Lint code - fmt Format code - build Build application - test Run test - lib Build library - dev Run development server - optimize Pre-bundle dependencies - preview Preview production build - doc Build documentation - cache Manage the task cache - install Install command. It will be passed to the package manager's install command currently - help Print this message or the help of the given subcommand(s) + run Run tasks + lint Lint code + fmt Format code + build Build application + test Run test + lib Build library + dev Run development server + preview Preview production build + doc Build documentation + cache Manage the task cache + install Install command. It will be passed to the package manager's install command currently + help Print this message or the help of the given subcommand(s) Arguments: [TASK] @@ -336,25 +335,6 @@ Options: -h, --help Display this message -> vite optimize -h # optimize help message -vite/ - -Usage: - $ vite optimize [root] - -Options: - --force [boolean] force the optimizer to ignore the cache and re-bundle - -c, --config [string] use specified config file - --base [string] public base path (default: /) - -l, --logLevel [string] info | warn | error | silent - --clearScreen [boolean] allow/disable clear screen when logging - --configLoader [string] use 'bundle' to bundle the config with Rolldown, or 'runner' (experimental) to process it on the fly, or 'native' (experimental) to load using the native runtime (default: bundle) - -d, --debug [feat] [string | boolean] show debug logs - -f, --filter [string] filter debug logs - -m, --mode [string] set env mode - -h, --help Display this message - - > vite preview -h # preview help message vite/ diff --git a/packages/cli/snap-tests/command-helper/steps.json b/packages/cli/snap-tests/command-helper/steps.json index d718292080..86853ca45a 100644 --- a/packages/cli/snap-tests/command-helper/steps.json +++ b/packages/cli/snap-tests/command-helper/steps.json @@ -10,7 +10,6 @@ "vite lint -h # lint help message", "vite build -h # build help message", "vite test -h # test help message", - "vite optimize -h # optimize help message", "vite preview -h # preview help message" ] } diff --git a/packages/cli/snap-tests/command-optimize/package.json b/packages/cli/snap-tests/command-optimize/package.json deleted file mode 100644 index 2c63c08510..0000000000 --- a/packages/cli/snap-tests/command-optimize/package.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/packages/cli/snap-tests/command-optimize/snap.txt b/packages/cli/snap-tests/command-optimize/snap.txt deleted file mode 100644 index 84b2eb9024..0000000000 --- a/packages/cli/snap-tests/command-optimize/snap.txt +++ /dev/null @@ -1,4 +0,0 @@ -[timeout]> vite optimize --force 2>&1 | head -3 # run optimize with force flag -manually calling optimizeDeps is deprecated. This is done automatically and does not need to be called manually. -9:32:42 PM [vite] (client) Forced re-optimization of dependencies -Optimizing dependencies: diff --git a/packages/cli/snap-tests/command-optimize/steps.json b/packages/cli/snap-tests/command-optimize/steps.json deleted file mode 100644 index 2f52ee3688..0000000000 --- a/packages/cli/snap-tests/command-optimize/steps.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ignoredPlatforms": ["win32"], - "env": { - "VITE_DISABLE_AUTO_INSTALL": "1" - }, - "commands": [ - "vite optimize --force 2>&1 | head -3 # run optimize with force flag" - ] -} diff --git a/packages/global/src/index.ts b/packages/global/src/index.ts index e90b3a38b5..d7ec385772 100644 --- a/packages/global/src/index.ts +++ b/packages/global/src/index.ts @@ -11,7 +11,6 @@ const LOCAL_CLI_COMMANDS = [ 'lib', 'doc', 'run', - 'optimize', 'preview', ]; From e56d5c80f797f28d86b6af25f752a868e562a3fa Mon Sep 17 00:00:00 2001 From: MK Date: Thu, 25 Dec 2025 21:49:09 +0800 Subject: [PATCH 4/4] feat(cli): default to dev command when no subcommand provided MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Running `vite` without arguments or with options (e.g., `vite --port 3000`) now defaults to the dev command, matching the behavior of the upstream Vite CLI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- packages/cli/binding/src/lib.rs | 75 ++++++++++++++----- .../snap-tests/command-dev-with-port/snap.txt | 3 + .../command-dev-with-port/steps.json | 3 +- .../cli/snap-tests/command-helper/snap.txt | 38 ++++++++++ .../cli/snap-tests/command-helper/steps.json | 3 +- 5 files changed, 103 insertions(+), 19 deletions(-) diff --git a/packages/cli/binding/src/lib.rs b/packages/cli/binding/src/lib.rs index d19b5b9fcb..e4534ac1fd 100644 --- a/packages/cli/binding/src/lib.rs +++ b/packages/cli/binding/src/lib.rs @@ -80,7 +80,8 @@ impl From for ResolveCommandResult { } } -static BUILTIN_COMMANDS: &[&str] = &["lint", "fmt", "build", "test", "doc", "lib", "preview"]; +static BUILTIN_COMMANDS: &[&str] = + &["dev", "lint", "fmt", "build", "test", "doc", "lib", "preview"]; /// Main entry point for the CLI, called from JavaScript. /// @@ -267,30 +268,70 @@ fn js_error_to_resolve_universal_vite_config_error(err: napi::Error) -> Error { fn parse_args() -> Args { // ArgsOs [node, vite-plus, ...] let mut raw_args = std::env::args_os().skip(2); - if let Some(first) = raw_args.next() - && let Some(first) = first.to_str() - && BUILTIN_COMMANDS.contains(&first) - { - let forwarded_args = raw_args + + // No arguments provided, default to dev command + let Some(first) = raw_args.next() else { + return Args { + task: None, + task_args: vec![], + commands: Commands::Dev { args: vec![] }, + debug: false, + no_debug: true, + }; + }; + + // If first arg is not valid UTF-8, fall through to clap parsing + let Some(first_str) = first.to_str() else { + return Args::parse_from(std::env::args_os().skip(1)); + }; + + // Collect remaining args for potential forwarding + let remaining_args: Vec<_> = raw_args.collect(); + + // Handle builtin commands with fast-path parsing (bypasses clap for better arg forwarding) + if let Some(cmd) = parse_builtin_command(first_str, &remaining_args) { + return cmd; + } + + // If first arg starts with '-' but is NOT a help/version flag, treat as options for dev command + // e.g. `vite --port 3000` should be treated as `vite dev --port 3000` + if first_str.starts_with('-') && !matches!(first_str, "-h" | "--help" | "-V" | "--version") { + let forwarded_args: Vec = std::iter::once(first) + .chain(remaining_args) .map(|a| a.into_string().unwrap_or_else(|os_str| os_str.to_string_lossy().into_owned())) .collect(); return Args { task: None, task_args: vec![], - commands: match first { - "lint" => Commands::Lint { args: forwarded_args }, - "fmt" => Commands::Fmt { args: forwarded_args }, - "build" => Commands::Build { args: forwarded_args }, - "test" => Commands::Test { args: forwarded_args }, - "doc" => Commands::Doc { args: forwarded_args }, - "lib" => Commands::Lib { args: forwarded_args }, - "preview" => Commands::Preview { args: forwarded_args }, - _ => unreachable!(), - }, + commands: Commands::Dev { args: forwarded_args }, debug: false, no_debug: true, }; } - // Parse CLI arguments (skip first arg which is the node binary) + + // Fall through to clap parsing for other commands (run, cache, install, help, etc.) Args::parse_from(std::env::args_os().skip(1)) } + +fn parse_builtin_command(cmd: &str, raw_args: &[std::ffi::OsString]) -> Option { + if !BUILTIN_COMMANDS.contains(&cmd) { + return None; + } + + let forwarded_args: Vec = + raw_args.iter().map(|a| a.to_string_lossy().into_owned()).collect(); + + let commands = match cmd { + "dev" => Commands::Dev { args: forwarded_args }, + "lint" => Commands::Lint { args: forwarded_args }, + "fmt" => Commands::Fmt { args: forwarded_args }, + "build" => Commands::Build { args: forwarded_args }, + "test" => Commands::Test { args: forwarded_args }, + "doc" => Commands::Doc { args: forwarded_args }, + "lib" => Commands::Lib { args: forwarded_args }, + "preview" => Commands::Preview { args: forwarded_args }, + _ => return None, + }; + + Some(Args { task: None, task_args: vec![], commands, debug: false, no_debug: true }) +} diff --git a/packages/cli/snap-tests/command-dev-with-port/snap.txt b/packages/cli/snap-tests/command-dev-with-port/snap.txt index 44d205d25d..f58ae58df8 100644 --- a/packages/cli/snap-tests/command-dev-with-port/snap.txt +++ b/packages/cli/snap-tests/command-dev-with-port/snap.txt @@ -1,2 +1,5 @@ > vite dev --port 12312312312 2>&1 | grep RangeError # intentionally use an invalid port (exceeds 0-65535) to trigger RangeError RangeError [ERR_SOCKET_BAD_PORT]: options.port should be >= 0 and < 65536. Received type number (12312312312). + +> vite --port 12312312313 2>&1 | grep RangeError # vite without args should be alias to dev command +RangeError [ERR_SOCKET_BAD_PORT]: options.port should be >= 0 and < 65536. Received type number (12312312313). diff --git a/packages/cli/snap-tests/command-dev-with-port/steps.json b/packages/cli/snap-tests/command-dev-with-port/steps.json index 37c6780a68..8eea5d917c 100644 --- a/packages/cli/snap-tests/command-dev-with-port/steps.json +++ b/packages/cli/snap-tests/command-dev-with-port/steps.json @@ -4,6 +4,7 @@ "VITE_DISABLE_AUTO_INSTALL": "1" }, "commands": [ - "vite dev --port 12312312312 2>&1 | grep RangeError # intentionally use an invalid port (exceeds 0-65535) to trigger RangeError" + "vite dev --port 12312312312 2>&1 | grep RangeError # intentionally use an invalid port (exceeds 0-65535) to trigger RangeError", + "vite --port 12312312313 2>&1 | grep RangeError # vite without args should be alias to dev command" ] } diff --git a/packages/cli/snap-tests/command-helper/snap.txt b/packages/cli/snap-tests/command-helper/snap.txt index ca0974da1f..a55503e37b 100644 --- a/packages/cli/snap-tests/command-helper/snap.txt +++ b/packages/cli/snap-tests/command-helper/snap.txt @@ -357,3 +357,41 @@ Options: -m, --mode [string] set env mode -h, --help Display this message + +> vite dev -h # dev help message +vite/ + +Usage: + $ vite [root] + +Commands: + [root] start dev server + build [root] build for production + optimize [root] pre-bundle dependencies (deprecated, the pre-bundle process runs automatically and does not need to be called) + preview [root] locally preview production build + +For more info, run any command with the `--help` flag: + $ vite --help + $ vite build --help + $ vite optimize --help + $ vite preview --help + +Options: + --host [host] [string] specify hostname + --port [number] specify port + --open [path] [boolean | string] open browser on startup + --cors [boolean] enable CORS + --strictPort [boolean] exit if specified port is already in use + --force [boolean] force the optimizer to ignore the cache and re-bundle + --experimentalBundle [boolean] use experimental full bundle mode (this is highly experimental) + -c, --config [string] use specified config file + --base [string] public base path (default: /) + -l, --logLevel [string] info | warn | error | silent + --clearScreen [boolean] allow/disable clear screen when logging + --configLoader [string] use 'bundle' to bundle the config with Rolldown, or 'runner' (experimental) to process it on the fly, or 'native' (experimental) to load using the native runtime (default: bundle) + -d, --debug [feat] [string | boolean] show debug logs + -f, --filter [string] filter debug logs + -m, --mode [string] set env mode + -h, --help Display this message + -v, --version Display version number + diff --git a/packages/cli/snap-tests/command-helper/steps.json b/packages/cli/snap-tests/command-helper/steps.json index 86853ca45a..c9b7cffc1c 100644 --- a/packages/cli/snap-tests/command-helper/steps.json +++ b/packages/cli/snap-tests/command-helper/steps.json @@ -10,6 +10,7 @@ "vite lint -h # lint help message", "vite build -h # build help message", "vite test -h # test help message", - "vite preview -h # preview help message" + "vite preview -h # preview help message", + "vite dev -h # dev help message" ] }