diff --git a/CLAUDE.md b/CLAUDE.md index 03ebcd7d9..06b3de101 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -39,7 +39,7 @@ Test fixtures and snapshots: ## CLI Usage ```bash -# Run a task defined in vite.config.json +# Run a task defined in vite-task.json vite run # run task in current package vite run # # run task in specific package vite run -r # run task in all packages (recursive) @@ -67,7 +67,7 @@ vite lint [args...] # run oxlint ## Task Configuration -Tasks are defined in `vite.config.json`: +Tasks are defined in `vite-task.json`: ```json { @@ -83,7 +83,7 @@ Tasks are defined in `vite.config.json`: ## Task Dependencies -1. **Explicit**: Defined via `dependsOn` in `vite.config.json` (skip with `--ignore-depends-on`) +1. **Explicit**: Defined via `dependsOn` in `vite-task.json` (skip with `--ignore-depends-on`) 2. **Topological**: Based on package.json dependencies - With `-r/--recursive`: runs task across all packages in dependency order - With `-t/--transitive`: runs task in current package and its dependencies @@ -116,4 +116,4 @@ These patterns are enforced by `.clippy.toml`: ## Quick Reference - **Task Format**: `package#task` (e.g., `app#build`, `@test/utils#lint`) -- **Config File**: `vite.config.json` in each package +- **Config File**: `vite-task.json` in each package diff --git a/crates/vite_path/src/absolute/mod.rs b/crates/vite_path/src/absolute/mod.rs index 98ffe860a..4e0ed98c5 100644 --- a/crates/vite_path/src/absolute/mod.rs +++ b/crates/vite_path/src/absolute/mod.rs @@ -31,6 +31,12 @@ impl Debug for AbsolutePath { } } +impl Display for AbsolutePath { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Display::fmt(&self.0.display(), f) + } +} + impl Serialize for AbsolutePath { fn serialize(&self, serializer: S) -> Result where diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/associate-existing-cache/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/associate-existing-cache/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/associate-existing-cache/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/builtin-different-cwd/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/builtin-different-cwd/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/builtin-different-cwd/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/builtin-non-zero-exit/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/builtin-non-zero-exit/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/builtin-non-zero-exit/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-disabled/vite.config.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-disabled/vite-task.json similarity index 89% rename from crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-disabled/vite.config.json rename to crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-disabled/vite-task.json index 0de4fd889..e0b5cafa9 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-disabled/vite.config.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-disabled/vite-task.json @@ -1,4 +1,5 @@ { + "cacheScripts": true, "tasks": { "no-cache-task": { "command": "print-file test.txt", diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-command-change/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-command-change/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-command-change/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots.toml b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots.toml index 1a2e321aa..93bd65931 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots.toml +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots.toml @@ -25,16 +25,16 @@ steps = [ name = "pass-through env added" steps = [ "vite run test # cache miss", - "json-edit vite.config.json \"_.tasks.test.passThroughEnvs = ['MY_PASSTHROUGH']\" # add pass-through env", + "json-edit vite-task.json \"_.tasks.test.passThroughEnvs = ['MY_PASSTHROUGH']\" # add pass-through env", "vite run test # cache miss: pass-through env added", ] [[e2e]] name = "pass-through env removed" steps = [ - "json-edit vite.config.json \"_.tasks.test.passThroughEnvs = ['MY_PASSTHROUGH']\" # setup", + "json-edit vite-task.json \"_.tasks.test.passThroughEnvs = ['MY_PASSTHROUGH']\" # setup", "vite run test # cache miss", - "json-edit vite.config.json \"delete _.tasks.test.passThroughEnvs\" # remove pass-through env", + "json-edit vite-task.json \"delete _.tasks.test.passThroughEnvs\" # remove pass-through env", "vite run test # cache miss: pass-through env removed", ] @@ -44,7 +44,7 @@ steps = [ "vite run test # cache miss", "mkdir -p subfolder", "cp test.txt subfolder/test.txt", - "json-edit vite.config.json \"_.tasks.test.cwd = 'subfolder'\" # change cwd", + "json-edit vite-task.json \"_.tasks.test.cwd = 'subfolder'\" # change cwd", "vite run test # cache miss: cwd changed", ] diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots/cwd changed.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots/cwd changed.snap index fe831b276..02264c044 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots/cwd changed.snap +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots/cwd changed.snap @@ -26,7 +26,7 @@ Task Details: > cp test.txt subfolder/test.txt -> json-edit vite.config.json "_.tasks.test.cwd = 'subfolder'" # change cwd +> json-edit vite-task.json "_.tasks.test.cwd = 'subfolder'" # change cwd > vite run test # cache miss: cwd changed ~/subfolder$ print-file test.txt ✗ cache miss: working directory changed, executing diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots/pass-through env added.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots/pass-through env added.snap index 805fc64c7..fa63d424c 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots/pass-through env added.snap +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots/pass-through env added.snap @@ -22,7 +22,7 @@ Task Details: → Cache miss: no previous cache entry found ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -> json-edit vite.config.json "_.tasks.test.passThroughEnvs = ['MY_PASSTHROUGH']" # add pass-through env +> json-edit vite-task.json "_.tasks.test.passThroughEnvs = ['MY_PASSTHROUGH']" # add pass-through env > vite run test # cache miss: pass-through env added $ print-file test.txt ✗ cache miss: pass-through env config changed, executing diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots/pass-through env removed.snap b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots/pass-through env removed.snap index b5b4596f2..7de44e70e 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots/pass-through env removed.snap +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/snapshots/pass-through env removed.snap @@ -4,7 +4,7 @@ assertion_line: 203 expression: e2e_outputs input_file: crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons --- -> json-edit vite.config.json "_.tasks.test.passThroughEnvs = ['MY_PASSTHROUGH']" # setup +> json-edit vite-task.json "_.tasks.test.passThroughEnvs = ['MY_PASSTHROUGH']" # setup > vite run test # cache miss $ print-file test.txt @@ -24,7 +24,7 @@ Task Details: → Cache miss: no previous cache entry found ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -> json-edit vite.config.json "delete _.tasks.test.passThroughEnvs" # remove pass-through env +> json-edit vite-task.json "delete _.tasks.test.passThroughEnvs" # remove pass-through env > vite run test # cache miss: pass-through env removed $ print-file test.txt ✗ cache miss: pass-through env config changed, executing diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/vite.config.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/vite-task.json similarity index 84% rename from crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/vite.config.json rename to crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/vite-task.json index 73eb02696..81a1babf4 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/vite.config.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/vite-task.json @@ -1,4 +1,5 @@ { + "cacheScripts": true, "tasks": { "test": { "command": "print-file test.txt", diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/colon-in-name/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/colon-in-name/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/colon-in-name/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/e2e-env-test/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/e2e-env-test/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/e2e-env-test/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/e2e-lint-cache/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/e2e-lint-cache/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/e2e-lint-cache/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/error_cycle_dependency/vite.config.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/error_cycle_dependency/vite-task.json similarity index 88% rename from crates/vite_task_bin/tests/e2e_snapshots/fixtures/error_cycle_dependency/vite.config.json rename to crates/vite_task_bin/tests/e2e_snapshots/fixtures/error_cycle_dependency/vite-task.json index 82baa8300..46b744586 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/error_cycle_dependency/vite.config.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/error_cycle_dependency/vite-task.json @@ -1,4 +1,5 @@ { + "cacheScripts": true, "tasks": { "task-a": { "command": "echo a", diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exit-codes/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/individual-cache-for-adt-args/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/individual-cache-for-adt-args/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/individual-cache-for-adt-args/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/individual-cache-for-envs/vite.config.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/individual-cache-for-envs/vite-task.json similarity index 83% rename from crates/vite_task_bin/tests/e2e_snapshots/fixtures/individual-cache-for-envs/vite.config.json rename to crates/vite_task_bin/tests/e2e_snapshots/fixtures/individual-cache-for-envs/vite-task.json index 8ef0caca1..419def71b 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/individual-cache-for-envs/vite.config.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/individual-cache-for-envs/vite-task.json @@ -1,4 +1,5 @@ { + "cacheScripts": true, "tasks": { "hello": { "command": "print-env FOO", diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/lint-dot-git/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/lint-dot-git/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/lint-dot-git/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/replay-logs-chronological-order/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/replay-logs-chronological-order/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/replay-logs-chronological-order/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/same-name-as-builtin/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/same-name-as-builtin/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/same-name-as-builtin/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/shared-caching-inputs/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/shared-caching-inputs/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/shared-caching-inputs/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/signal-exit/vite.config.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/signal-exit/vite-task.json similarity index 80% rename from crates/vite_task_bin/tests/e2e_snapshots/fixtures/signal-exit/vite.config.json rename to crates/vite_task_bin/tests/e2e_snapshots/fixtures/signal-exit/vite-task.json index 6407f2fbd..8c7ba7357 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/signal-exit/vite.config.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/signal-exit/vite-task.json @@ -1,4 +1,5 @@ { + "cacheScripts": true, "tasks": { "abort": { "command": "node -e \"process.kill(process.pid, 6)\"" diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-passthrough/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-passthrough/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-passthrough/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/task-no-trailing-newline/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/task-no-trailing-newline/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/task-no-trailing-newline/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite-task-smoke/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite-task-smoke/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/vite-task-smoke/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_graph/task-config.ts b/crates/vite_task_graph/run-config.ts similarity index 72% rename from crates/vite_task_graph/task-config.ts rename to crates/vite_task_graph/run-config.ts index 0c3db0443..0c68a8e11 100644 --- a/crates/vite_task_graph/task-config.ts +++ b/crates/vite_task_graph/run-config.ts @@ -36,4 +36,16 @@ export type Task = { } ); -export type Tasks = { [key in string]?: Task }; +export type RunConfig = { + /** + * Enable cache for all scripts from package.json. + * + * This option can only be set in the workspace root's config file. + * Setting it in a package's config will result in an error. + */ + cacheScripts?: boolean; + /** + * Task definitions + */ + tasks?: { [key in string]?: Task }; +}; diff --git a/crates/vite_task_graph/src/config/mod.rs b/crates/vite_task_graph/src/config/mod.rs index 93fac6270..28157d088 100644 --- a/crates/vite_task_graph/src/config/mod.rs +++ b/crates/vite_task_graph/src/config/mod.rs @@ -4,7 +4,7 @@ use std::{collections::HashSet, sync::Arc}; use monostate::MustBe; use serde::Serialize; -pub use user::{UserCacheConfig, UserConfigFile, UserTaskConfig}; +pub use user::{EnabledCacheConfig, UserCacheConfig, UserRunConfig, UserTaskConfig}; use vite_path::AbsolutePath; use vite_str::Str; @@ -91,14 +91,28 @@ pub enum ResolveTaskConfigError { } impl ResolvedTaskConfig { - /// Resolve from package.json script only + /// Resolve from package.json script only (no vite-task.json config for this task) + /// + /// The `cache_scripts` parameter determines whether caching is enabled for the script. + /// When `true`, caching is enabled with default settings. + /// When `false`, caching is disabled. pub fn resolve_package_json_script( package_dir: &Arc, package_json_script: &str, + cache_scripts: bool, ) -> Self { + let cache_config = if cache_scripts { + UserCacheConfig::Enabled { + cache: None, + enabled_cache_config: EnabledCacheConfig { envs: None, pass_through_envs: None }, + } + } else { + UserCacheConfig::Disabled { cache: MustBe!(false) } + }; + let options = UserTaskOptions { cache_config, ..Default::default() }; Self { command: package_json_script.into(), - resolved_options: ResolvedTaskOptions::resolve(UserTaskOptions::default(), package_dir), + resolved_options: ResolvedTaskOptions::resolve(options, package_dir), } } diff --git a/crates/vite_task_graph/src/config/user.rs b/crates/vite_task_graph/src/config/user.rs index 394453fa1..d5292bda5 100644 --- a/crates/vite_task_graph/src/config/user.rs +++ b/crates/vite_task_graph/src/config/user.rs @@ -92,22 +92,24 @@ pub struct UserTaskConfig { pub options: UserTaskOptions, } -/// User configuration file structure for `vite.config.*` -#[derive(Debug, Deserialize)] -pub struct UserConfigFile { - pub tasks: UserConfigTasks, -} - -/// Type of the `tasks` field in `vite.config.*` +/// User configuration structure for `run` field in `vite.config.*` #[derive(Debug, Default, Deserialize)] -#[cfg_attr(test, derive(TS))] -#[serde(transparent)] -#[cfg_attr(test, ts(rename = "Tasks"))] -pub struct UserConfigTasks(pub HashMap); +#[cfg_attr(test, derive(TS), ts(optional_fields, rename = "RunConfig"))] +#[serde(rename_all = "camelCase")] +pub struct UserRunConfig { + /// Enable cache for all scripts from package.json. + /// + /// This option can only be set in the workspace root's config file. + /// Setting it in a package's config will result in an error. + pub cache_scripts: Option, + + /// Task definitions + pub tasks: Option>, +} -impl UserConfigTasks { - /// TypeScript type definitions for user task configuration. - pub const TS_TYPE: &str = include_str!("../../task-config.ts"); +impl UserRunConfig { + /// TypeScript type definitions for user run configuration. + pub const TS_TYPE: &str = include_str!("../../run-config.ts"); /// Generates TypeScript type definitions for user task configuration. #[cfg(test)] @@ -155,7 +157,7 @@ impl UserConfigTasks { .expect("oxfmt not found in packages/tools"); let mut child = Command::new(oxfmt_path) - .arg("--stdin-filepath=task-config.ts") + .arg("--stdin-filepath=run-config.ts") .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() @@ -179,13 +181,13 @@ impl UserConfigTasks { mod ts_tests { use std::{env, path::PathBuf}; - use super::UserConfigTasks; + use super::UserRunConfig; #[test] fn typescript_generation() { let file_path = - PathBuf::from(std::env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("task-config.ts"); - let ts = UserConfigTasks::generate_ts_definition().replace("\r", ""); + PathBuf::from(std::env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("run-config.ts"); + let ts = UserRunConfig::generate_ts_definition().replace("\r", ""); if env::var("VT_UPDATE_TS_TYPES").unwrap_or_default() == "1" { std::fs::write(&file_path, ts).unwrap(); diff --git a/crates/vite_task_graph/src/lib.rs b/crates/vite_task_graph/src/lib.rs index 5190a571e..e0e8fa74f 100644 --- a/crates/vite_task_graph/src/lib.rs +++ b/crates/vite_task_graph/src/lib.rs @@ -11,7 +11,7 @@ use std::{ sync::Arc, }; -use config::{ResolvedTaskConfig, UserConfigFile}; +use config::{ResolvedTaskConfig, UserRunConfig}; use package_graph::IndexedPackageGraph; use petgraph::{ graph::{DefaultIx, DiGraph, EdgeIndex, IndexType, NodeIndex}, @@ -112,6 +112,11 @@ pub enum TaskGraphLoadError { #[source] error: SpecifierLookupError, }, + + #[error( + "`cacheScripts` can only be set in the workspace root config, but found in {package_path}" + )] + CacheScriptsInNonRootPackage { package_path: Arc }, } /// Error when looking up a task by its specifier. @@ -198,10 +203,41 @@ impl IndexedTaskGraph { let mut node_indices_by_task_id: HashMap = HashMap::with_capacity(task_graph.node_count()); - // Load task nodes into `task_graph` + // First pass: load all configs, extract cacheScripts from root, validate + let mut cache_scripts = false; // Default: disabled + let mut package_configs: Vec<(PackageNodeIndex, Arc, UserRunConfig)> = + Vec::with_capacity(package_graph.node_count()); + for package_index in package_graph.node_indices() { let package = &package_graph[package_index]; let package_dir: Arc = workspace_root.path.join(&package.path).into(); + let is_workspace_root = package.path.as_str().is_empty(); + + let user_config = config_loader + .load_user_config_file(&package_dir) + .await + .map_err(|error| TaskGraphLoadError::ConfigLoadError { + error, + package_path: package_dir.clone(), + })? + .unwrap_or_default(); + + if let Some(current_cache_scripts) = user_config.cache_scripts { + if is_workspace_root { + cache_scripts = current_cache_scripts; + } else { + return Err(TaskGraphLoadError::CacheScriptsInNonRootPackage { + package_path: package_dir.clone(), + }); + } + } + + package_configs.push((package_index, package_dir, user_config)); + } + + // Second pass: create task nodes using cache_scripts value + for (package_index, package_dir, user_config) in package_configs { + let package = &package_graph[package_index]; // Collect package.json scripts into a mutable map for draining lookup. let mut package_json_scripts: HashMap<&str, &str> = package @@ -211,13 +247,7 @@ impl IndexedTaskGraph { .map(|(name, value)| (name.as_str(), value.as_str())) .collect(); - // Load vite.config.* for the package - let user_config: UserConfigFile = - config_loader.load_user_config_file(&package_dir).await.map_err(|error| { - TaskGraphLoadError::ConfigLoadError { error, package_path: package_dir.clone() } - })?; - - for (task_name, task_user_config) in user_config.tasks.0 { + for (task_name, task_user_config) in user_config.tasks.unwrap_or_default() { // For each task defined in vite.config.*, look up the corresponding package.json script (if any) let package_json_script = package_json_scripts.remove(task_name.as_str()); @@ -260,6 +290,7 @@ impl IndexedTaskGraph { let resolved_config = ResolvedTaskConfig::resolve_package_json_script( &package_dir, package_json_script, + cache_scripts, ); let node_index = task_graph.add_node(TaskNode { task_display: TaskDisplay { diff --git a/crates/vite_task_graph/src/loader.rs b/crates/vite_task_graph/src/loader.rs index 0b699bb79..8a192fdcd 100644 --- a/crates/vite_task_graph/src/loader.rs +++ b/crates/vite_task_graph/src/loader.rs @@ -2,18 +2,18 @@ use std::fmt::Debug; use vite_path::AbsolutePath; -use crate::config::UserConfigFile; +use crate::config::UserRunConfig; -/// Loader trait for loading user configuration files (vite.config.*). +/// Loader trait for loading user configuration files (vite-task.json). #[async_trait::async_trait(?Send)] pub trait UserConfigLoader: Debug + Send + Sync { async fn load_user_config_file( &self, package_path: &AbsolutePath, - ) -> anyhow::Result; + ) -> anyhow::Result>; } -/// A `UserConfigLoader` implementation that only loads `vite.config.json`. +/// A `UserConfigLoader` implementation that only loads `vite-task.json`. /// /// This is mainly for examples and testing as it does not require Node.js environment. #[derive(Default, Debug)] @@ -24,16 +24,16 @@ impl UserConfigLoader for JsonUserConfigLoader { async fn load_user_config_file( &self, package_path: &AbsolutePath, - ) -> anyhow::Result { - let config_path = package_path.join("vite.config.json"); + ) -> anyhow::Result> { + let config_path = package_path.join("vite-task.json"); let config_content = match tokio::fs::read_to_string(&config_path).await { Ok(content) => content, Err(err) if err.kind() == std::io::ErrorKind::NotFound => { - return Ok(UserConfigFile { tasks: Default::default() }); + return Ok(None); } Err(err) => return Err(err.into()), }; - let user_config: UserConfigFile = serde_json::from_str(&config_content)?; - Ok(user_config) + let user_config: UserRunConfig = serde_json::from_str(&config_content)?; + Ok(Some(user_config)) } } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional-envs/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional-envs/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/additional-envs/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-keys/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-default/package.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-default/package.json new file mode 100644 index 000000000..6bfb25ccf --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-default/package.json @@ -0,0 +1,7 @@ +{ + "name": "@test/cache-scripts-default", + "scripts": { + "build": "echo building", + "test": "echo testing" + } +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-default/snapshots/task graph.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-default/snapshots/task graph.snap new file mode 100644 index 000000000..b20ad283c --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-default/snapshots/task graph.snap @@ -0,0 +1,49 @@ +--- +source: crates/vite_task_plan/tests/plan_snapshots/main.rs +expression: task_graph_json +input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-default +--- +[ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/cache-scripts-default", + "task_name": "build", + "package_path": "/" + }, + "resolved_config": { + "command": "echo building", + "resolved_options": { + "cwd": "/", + "cache_config": null + } + } + }, + "neighbors": [] + }, + { + "key": [ + "/", + "test" + ], + "node": { + "task_display": { + "package_name": "@test/cache-scripts-default", + "task_name": "test", + "package_path": "/" + }, + "resolved_config": { + "command": "echo testing", + "resolved_options": { + "cwd": "/", + "cache_config": null + } + } + }, + "neighbors": [] + } +] diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-enabled/package.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-enabled/package.json new file mode 100644 index 000000000..ee76392f1 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-enabled/package.json @@ -0,0 +1,7 @@ +{ + "name": "@test/cache-scripts-enabled", + "scripts": { + "build": "echo building", + "test": "echo testing" + } +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-enabled/snapshots/task graph.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-enabled/snapshots/task graph.snap new file mode 100644 index 000000000..457d41935 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-enabled/snapshots/task graph.snap @@ -0,0 +1,63 @@ +--- +source: crates/vite_task_plan/tests/plan_snapshots/main.rs +expression: task_graph_json +input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-enabled +--- +[ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/cache-scripts-enabled", + "task_name": "build", + "package_path": "/" + }, + "resolved_config": { + "command": "echo building", + "resolved_options": { + "cwd": "/", + "cache_config": { + "env_config": { + "fingerprinted_envs": [], + "pass_through_envs": [ + "" + ] + } + } + } + } + }, + "neighbors": [] + }, + { + "key": [ + "/", + "test" + ], + "node": { + "task_display": { + "package_name": "@test/cache-scripts-enabled", + "task_name": "test", + "package_path": "/" + }, + "resolved_config": { + "command": "echo testing", + "resolved_options": { + "cwd": "/", + "cache_config": { + "env_config": { + "fingerprinted_envs": [], + "pass_through_envs": [ + "" + ] + } + } + } + } + }, + "neighbors": [] + } +] diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-enabled/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-enabled/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-enabled/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/package.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/package.json new file mode 100644 index 000000000..5c37b711d --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/package.json @@ -0,0 +1,6 @@ +{ + "name": "@test/cache-scripts-error-non-root", + "scripts": { + "build": "echo building" + } +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/packages/pkg-a/package.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/packages/pkg-a/package.json new file mode 100644 index 000000000..3fadeff85 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/packages/pkg-a/package.json @@ -0,0 +1,6 @@ +{ + "name": "@test/pkg-a", + "scripts": { + "build": "echo building pkg-a" + } +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/packages/pkg-a/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/packages/pkg-a/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/packages/pkg-a/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/pnpm-workspace.yaml b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/pnpm-workspace.yaml new file mode 100644 index 000000000..924b55f42 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - packages/* diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/snapshots/task graph load error.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/snapshots/task graph load error.snap new file mode 100644 index 000000000..6807d8ccc --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root/snapshots/task graph load error.snap @@ -0,0 +1,6 @@ +--- +source: crates/vite_task_plan/tests/plan_snapshots/main.rs +expression: err_str +input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-error-non-root +--- +`cacheScripts` can only be set in the workspace root config, but found in /packages/pkg-a diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/package.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/package.json new file mode 100644 index 000000000..2990ff19d --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/package.json @@ -0,0 +1,7 @@ +{ + "name": "@test/cache-scripts-task-override", + "scripts": { + "build": "echo building", + "test": "echo testing" + } +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/task graph.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/task graph.snap new file mode 100644 index 000000000..fcf03317b --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/snapshots/task graph.snap @@ -0,0 +1,84 @@ +--- +source: crates/vite_task_plan/tests/plan_snapshots/main.rs +expression: task_graph_json +input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override +--- +[ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/cache-scripts-task-override", + "task_name": "build", + "package_path": "/" + }, + "resolved_config": { + "command": "echo building", + "resolved_options": { + "cwd": "/", + "cache_config": { + "env_config": { + "fingerprinted_envs": [], + "pass_through_envs": [ + "" + ] + } + } + } + } + }, + "neighbors": [] + }, + { + "key": [ + "/", + "deploy" + ], + "node": { + "task_display": { + "package_name": "@test/cache-scripts-task-override", + "task_name": "deploy", + "package_path": "/" + }, + "resolved_config": { + "command": "echo deploying", + "resolved_options": { + "cwd": "/", + "cache_config": { + "env_config": { + "fingerprinted_envs": [], + "pass_through_envs": [ + "" + ] + } + } + } + } + }, + "neighbors": [] + }, + { + "key": [ + "/", + "test" + ], + "node": { + "task_display": { + "package_name": "@test/cache-scripts-task-override", + "task_name": "test", + "package_path": "/" + }, + "resolved_config": { + "command": "echo testing", + "resolved_options": { + "cwd": "/", + "cache_config": null + } + } + }, + "neighbors": [] + } +] diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/vite-task.json new file mode 100644 index 000000000..5c71428c9 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-scripts-task-override/vite-task.json @@ -0,0 +1,8 @@ +{ + "tasks": { + "build": {}, + "deploy": { + "command": "echo deploying" + } + } +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-sharing/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-sharing/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-sharing/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/comprehensive-task-graph/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/comprehensive-task-graph/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/comprehensive-task-graph/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/conflict-test/packages/test-package/vite.config.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/conflict-test/packages/test-package/vite-task.json similarity index 100% rename from crates/vite_task_plan/tests/plan_snapshots/fixtures/conflict-test/packages/test-package/vite.config.json rename to crates/vite_task_plan/tests/plan_snapshots/fixtures/conflict-test/packages/test-package/vite-task.json diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/conflict-test/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/conflict-test/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/conflict-test/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/dependency-both-topo-and-explicit/packages/a/vite.config.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/dependency-both-topo-and-explicit/packages/a/vite-task.json similarity index 100% rename from crates/vite_task_plan/tests/plan_snapshots/fixtures/dependency-both-topo-and-explicit/packages/a/vite.config.json rename to crates/vite_task_plan/tests/plan_snapshots/fixtures/dependency-both-topo-and-explicit/packages/a/vite-task.json diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/dependency-both-topo-and-explicit/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/dependency-both-topo-and-explicit/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/dependency-both-topo-and-explicit/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/packages/another-empty/vite.config.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/packages/another-empty/vite-task.json similarity index 100% rename from crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/packages/another-empty/vite.config.json rename to crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/packages/another-empty/vite-task.json diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/packages/empty-name/vite.config.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/packages/empty-name/vite-task.json similarity index 100% rename from crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/packages/empty-name/vite.config.json rename to crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/packages/empty-name/vite-task.json diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/packages/normal-package/vite.config.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/packages/normal-package/vite-task.json similarity index 100% rename from crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/packages/normal-package/vite.config.json rename to crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/packages/normal-package/vite-task.json diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/empty-package-test/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/packages/app/vite.config.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/packages/app/vite-task.json similarity index 100% rename from crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/packages/app/vite.config.json rename to crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/packages/app/vite-task.json diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/packages/core/vite.config.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/packages/core/vite-task.json similarity index 100% rename from crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/packages/core/vite.config.json rename to crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/packages/core/vite-task.json diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/packages/utils/vite.config.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/packages/utils/vite-task.json similarity index 100% rename from crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/packages/utils/vite.config.json rename to crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/packages/utils/vite-task.json diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/explicit-deps-workspace/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/fingerprint-ignore-test/vite.config.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/fingerprint-ignore-test/vite-task.json similarity index 92% rename from crates/vite_task_plan/tests/plan_snapshots/fixtures/fingerprint-ignore-test/vite.config.json rename to crates/vite_task_plan/tests/plan_snapshots/fixtures/fingerprint-ignore-test/vite-task.json index effd7a428..f3583872e 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/fingerprint-ignore-test/vite.config.json +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/fingerprint-ignore-test/vite-task.json @@ -1,4 +1,5 @@ { + "cacheScripts": true, "tasks": { "create-files": { "command": "mkdir -p node_modules/pkg-a && echo '{\"name\":\"pkg-a\"}' > node_modules/pkg-a/package.json && echo 'content' > node_modules/pkg-a/index.js && mkdir -p dist && echo 'output' > dist/bundle.js", diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-tasks/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-tasks/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/nested-tasks/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/pnpm-workspace-packages-optional/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/pnpm-workspace-packages-optional/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/pnpm-workspace-packages-optional/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/recursive-topological-workspace/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/recursive-topological-workspace/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/recursive-topological-workspace/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell-fallback/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell-fallback/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/shell-fallback/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-in-subpackage/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-in-subpackage/vite-task.json new file mode 100644 index 000000000..1d0fe9f20 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-in-subpackage/vite-task.json @@ -0,0 +1,3 @@ +{ + "cacheScripts": true +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/packages/pkg-a/package.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/packages/pkg-a/package.json new file mode 100644 index 000000000..3fadeff85 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/packages/pkg-a/package.json @@ -0,0 +1,6 @@ +{ + "name": "@test/pkg-a", + "scripts": { + "build": "echo building pkg-a" + } +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/pnpm-workspace.yaml b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/pnpm-workspace.yaml new file mode 100644 index 000000000..924b55f42 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - packages/* diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/snapshots.toml b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/snapshots.toml new file mode 100644 index 000000000..432a4504a --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/snapshots.toml @@ -0,0 +1 @@ +# Test cases for workspace root without package.json diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/snapshots/task graph.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/snapshots/task graph.snap new file mode 100644 index 000000000..051e2c040 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/snapshots/task graph.snap @@ -0,0 +1,63 @@ +--- +source: crates/vite_task_plan/tests/plan_snapshots/main.rs +expression: task_graph_json +input_file: crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json +--- +[ + { + "key": [ + "/", + "deploy" + ], + "node": { + "task_display": { + "package_name": "", + "task_name": "deploy", + "package_path": "/" + }, + "resolved_config": { + "command": "echo deploying workspace", + "resolved_options": { + "cwd": "/", + "cache_config": { + "env_config": { + "fingerprinted_envs": [], + "pass_through_envs": [ + "" + ] + } + } + } + } + }, + "neighbors": [] + }, + { + "key": [ + "/packages/pkg-a", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/pkg-a", + "task_name": "build", + "package_path": "/packages/pkg-a" + }, + "resolved_config": { + "command": "echo building pkg-a", + "resolved_options": { + "cwd": "/packages/pkg-a", + "cache_config": { + "env_config": { + "fingerprinted_envs": [], + "pass_through_envs": [ + "" + ] + } + } + } + } + }, + "neighbors": [] + } +] diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/vite-task.json new file mode 100644 index 000000000..f07f1a9c6 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/workspace-root-no-package-json/vite-task.json @@ -0,0 +1,8 @@ +{ + "cacheScripts": true, + "tasks": { + "deploy": { + "command": "echo deploying workspace" + } + } +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/main.rs b/crates/vite_task_plan/tests/plan_snapshots/main.rs index 4c94b4ab0..0677eeacf 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/main.rs +++ b/crates/vite_task_plan/tests/plan_snapshots/main.rs @@ -97,10 +97,20 @@ fn run_case_inner( ) .unwrap(); + let task_graph_result = session.ensure_task_graph_loaded().await; + let task_graph = match task_graph_result { + Ok(task_graph) => task_graph, + Err(err) => { + let mut err_str = format!("{err:#}").replace(workspace_root_str, ""); + if cfg!(windows) { + err_str = err_str.replace('\\', "/"); + } + insta::assert_snapshot!("task graph load error", err_str); + return; + } + }; let task_graph_json = redact_snapshot( - &vite_graph_ser::SerializeByKey( - session.ensure_task_graph_loaded().await.unwrap().task_graph(), - ), + &vite_graph_ser::SerializeByKey(task_graph.task_graph()), workspace_root_str, ); insta::assert_json_snapshot!("task graph", task_graph_json); diff --git a/crates/vite_workspace/src/lib.rs b/crates/vite_workspace/src/lib.rs index db1d8e9bb..64965855e 100644 --- a/crates/vite_workspace/src/lib.rs +++ b/crates/vite_workspace/src/lib.rs @@ -257,27 +257,28 @@ pub fn load_package_graph( has_root_package = has_root_package || package_path.as_str().is_empty(); graph_builder.add_package(package_path, absolute_path.into(), package_json); } - // try add the root package anyway if the member globs do not include it. + // Always add the root package if member globs do not include it. if !has_root_package { let package_json_path = workspace_root.path.join("package.json"); - match fs::read(&package_json_path) { + let package_json = match fs::read(&package_json_path) { Ok(content) => { let package_json_path: Arc = package_json_path.into(); - let package_json: PackageJson = serde_json::from_slice(&content).map_err(|e| { - Error::SerdeJson { file_path: package_json_path, serde_json_error: e } - })?; - graph_builder.add_package( - RelativePathBuf::default(), - Arc::clone(&workspace_root.path), - package_json, - ); + serde_json::from_slice(&content).map_err(|e| Error::SerdeJson { + file_path: package_json_path, + serde_json_error: e, + })? } - Err(err) => { - if err.kind() != io::ErrorKind::NotFound { - return Err(err.into()); - } + Err(err) if err.kind() == io::ErrorKind::NotFound => { + // No package.json at root - use empty default + PackageJson::default() } - } + Err(err) => return Err(err.into()), + }; + graph_builder.add_package( + RelativePathBuf::default(), + Arc::clone(&workspace_root.path), + package_json, + ); } graph_builder.build() } @@ -616,8 +617,8 @@ mod tests { let graph = discover_package_graph(temp_dir_path).unwrap(); - // Should have 2 nodes but no edges (nameless package can't be referenced) - assert_eq!(graph.node_count(), 2); + // Should have 3 nodes (nameless, pkg-a, root) but no edges (nameless package can't be referenced) + assert_eq!(graph.node_count(), 3); assert_eq!(graph.edge_count(), 0); } @@ -703,8 +704,8 @@ mod tests { let graph = discover_package_graph(temp_dir_path).unwrap(); - // Should have 2 nodes and 2 edges (circular) - assert_eq!(graph.node_count(), 2); + // Should have 3 nodes (pkg-a, pkg-b, root) and 2 edges (circular between a and b) + assert_eq!(graph.node_count(), 3); assert_eq!(graph.edge_count(), 2); // Verify both edges exist diff --git a/dprint.json b/dprint.json index 0484a32cd..5dc442769 100644 --- a/dprint.json +++ b/dprint.json @@ -15,7 +15,7 @@ "excludes": [ "crates/fspy_detours_sys/detours", "pnpm-lock.yaml", - "crates/vite_task_graph/task-config.ts" + "crates/vite_task_graph/run-config.ts" ], "plugins": [ "https://plugins.dprint.dev/typescript-0.94.0.wasm",