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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-disabled/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-disabled/vite-task.json index e0b5cafa..c1d2fecf 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-disabled/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-disabled/vite-task.json @@ -1,5 +1,5 @@ { - "cacheScripts": true, + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/vite-task.json index 81a1babf..a364da13 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-miss-reasons/vite-task.json @@ -1,5 +1,5 @@ { - "cacheScripts": true, + "cache": true, "tasks": { "test": { "command": "print-file test.txt", diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-subcommand/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-subcommand/vite-task.json index d1bedfe4..0622bca6 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-subcommand/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/cache-subcommand/vite-task.json @@ -1,5 +1,5 @@ { - "cacheScripts": true, + "cache": true, "tasks": { "cached-task": { "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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/error_cycle_dependency/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/error_cycle_dependency/vite-task.json index 46b74458..25c64078 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/error_cycle_dependency/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/error_cycle_dependency/vite-task.json @@ -1,5 +1,5 @@ { - "cacheScripts": true, + "cache": true, "tasks": { "task-a": { "command": "echo a", diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exec-api/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exec-api/vite-task.json index 1d0fe9f2..d548edfa 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exec-api/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/exec-api/vite-task.json @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/filter-unmatched/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/filter-unmatched/vite-task.json index 1d0fe9f2..d548edfa 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/filter-unmatched/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/filter-unmatched/vite-task.json @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/individual-cache-for-envs/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/individual-cache-for-envs/vite-task.json index 419def71..32c2885c 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/individual-cache-for-envs/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/individual-cache-for-envs/vite-task.json @@ -1,5 +1,5 @@ { - "cacheScripts": true, + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/signal-exit/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/signal-exit/vite-task.json index 8c7ba735..538ef2dd 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/signal-exit/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/signal-exit/vite-task.json @@ -1,5 +1,5 @@ { - "cacheScripts": true, + "cache": true, "tasks": { "abort": { "command": "node -e \"process.kill(process.pid, 6)\"" diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-inheritance/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-inheritance/vite-task.json index 3e5addfb..3d530052 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-inheritance/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdin-inheritance/vite-task.json @@ -1,5 +1,5 @@ { - "cacheScripts": true, + "cache": true, "tasks": { "read-stdin": { "command": "read-stdin", diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/vite-task.json index 626205d1..cdd05d51 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-detection/vite-task.json @@ -1,5 +1,5 @@ { - "cacheScripts": true, + "cache": true, "tasks": { "check-tty": { "command": "check-tty", diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/vite-task.json index abcca7dd..9514c5d8 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/stdio-graph-criteria/vite-task.json @@ -1,5 +1,5 @@ { - "cacheScripts": true, + "cache": true, "tasks": { "check-tty": { "command": "check-tty", diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/summary-output/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/summary-output/vite-task.json index 1d0fe9f2..d548edfa 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/summary-output/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/summary-output/vite-task.json @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } diff --git a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/topological-execution-order/vite-task.json b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/topological-execution-order/vite-task.json index 1d0fe9f2..d548edfa 100644 --- a/crates/vite_task_bin/tests/e2e_snapshots/fixtures/topological-execution-order/vite-task.json +++ b/crates/vite_task_bin/tests/e2e_snapshots/fixtures/topological-execution-order/vite-task.json @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": 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 index 43bed5d7..f8e740b3 100644 --- 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 @@ -1,4 +1,4 @@ { // Smoke test: enables caching for all package.json scripts. - "cacheScripts": true + "cache": true } diff --git a/crates/vite_task_graph/run-config.ts b/crates/vite_task_graph/run-config.ts index 0c68a8e1..7944ae70 100644 --- a/crates/vite_task_graph/run-config.ts +++ b/crates/vite_task_graph/run-config.ts @@ -1,3 +1,27 @@ +export type UserGlobalCacheConfig = + | boolean + | { + /** + * Enable caching for package.json scripts not defined in the `tasks` map. + * + * When `false`, package.json scripts will not be cached. + * When `true`, package.json scripts will be cached with default settings. + * + * Default: `false` + */ + scripts?: boolean; + /** + * Global cache kill switch for task entries. + * + * When `false`, overrides all tasks to disable caching, even tasks with `cache: true`. + * When `true`, respects each task's individual `cache` setting + * (each task's `cache` defaults to `true` if omitted). + * + * Default: `true` + */ + tasks?: boolean; + }; + export type Task = { /** * The command to run for the task. @@ -38,12 +62,12 @@ export type Task = { export type RunConfig = { /** - * Enable cache for all scripts from package.json. + * Root-level cache configuration. * * 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; + cache?: UserGlobalCacheConfig; /** * Task definitions */ diff --git a/crates/vite_task_graph/src/config/mod.rs b/crates/vite_task_graph/src/config/mod.rs index 7a615b97..6512c3f2 100644 --- a/crates/vite_task_graph/src/config/mod.rs +++ b/crates/vite_task_graph/src/config/mod.rs @@ -5,7 +5,10 @@ use std::sync::Arc; use monostate::MustBe; use rustc_hash::FxHashSet; use serde::Serialize; -pub use user::{EnabledCacheConfig, UserCacheConfig, UserRunConfig, UserTaskConfig}; +pub use user::{ + EnabledCacheConfig, ResolvedGlobalCacheConfig, UserCacheConfig, UserGlobalCacheConfig, + UserRunConfig, UserTaskConfig, +}; use vite_path::AbsolutePath; use vite_str::Str; diff --git a/crates/vite_task_graph/src/config/user.rs b/crates/vite_task_graph/src/config/user.rs index 0607ed98..bf55eaec 100644 --- a/crates/vite_task_graph/src/config/user.rs +++ b/crates/vite_task_graph/src/config/user.rs @@ -111,17 +111,78 @@ pub struct UserTaskConfig { pub options: UserTaskOptions, } +/// Root-level cache configuration. +/// +/// Controls caching behavior for the entire workspace. +/// +/// - `true` is equivalent to `{ scripts: true, tasks: true }` — enables caching for both +/// package.json scripts and task entries. +/// - `false` is equivalent to `{ scripts: false, tasks: false }` — disables all caching. +/// - When omitted, defaults to `{ scripts: false, tasks: true }`. +/// +/// 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. +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq)] +// TS derive macro generates code using std types that clippy disallows; skip derive during linting +#[cfg_attr(all(test, not(clippy)), derive(TS), ts(optional_fields))] +#[serde(untagged, deny_unknown_fields)] +pub enum UserGlobalCacheConfig { + Bool(bool), + /// Detailed cache configuration with separate control for scripts and tasks. + Detailed { + /// Enable caching for package.json scripts not defined in the `tasks` map. + /// + /// When `false`, package.json scripts will not be cached. + /// When `true`, package.json scripts will be cached with default settings. + /// + /// Default: `false` + scripts: Option, + + /// Global cache kill switch for task entries. + /// + /// When `false`, overrides all tasks to disable caching, even tasks with `cache: true`. + /// When `true`, respects each task's individual `cache` setting + /// (each task's `cache` defaults to `true` if omitted). + /// + /// Default: `true` + tasks: Option, + }, +} + +/// Resolved global cache configuration with concrete boolean values. +pub struct ResolvedGlobalCacheConfig { + pub scripts: bool, + pub tasks: bool, +} + +impl ResolvedGlobalCacheConfig { + /// Resolve from an optional user config, using defaults when `None`. + /// + /// Default: `{ scripts: false, tasks: true }` + #[must_use] + pub fn resolve_from(config: Option<&UserGlobalCacheConfig>) -> Self { + match config { + None => Self { scripts: false, tasks: true }, + Some(UserGlobalCacheConfig::Bool(true)) => Self { scripts: true, tasks: true }, + Some(UserGlobalCacheConfig::Bool(false)) => Self { scripts: false, tasks: false }, + Some(UserGlobalCacheConfig::Detailed { scripts, tasks }) => { + Self { scripts: scripts.unwrap_or(false), tasks: tasks.unwrap_or(true) } + } + } + } +} + /// User configuration structure for `run` field in `vite.config.*` #[derive(Debug, Default, Deserialize)] // TS derive macro generates code using std types that clippy disallows; skip derive during linting #[cfg_attr(all(test, not(clippy)), derive(TS), ts(optional_fields, rename = "RunConfig"))] #[serde(rename_all = "camelCase")] pub struct UserRunConfig { - /// Enable cache for all scripts from package.json. + /// Root-level cache configuration. /// /// 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, + pub cache: Option, /// Task definitions pub tasks: Option>, @@ -315,4 +376,63 @@ mod tests { }); assert!(serde_json::from_value::(user_config_json).is_err()); } + + #[test] + fn test_global_cache_bool_true() { + let config: UserGlobalCacheConfig = serde_json::from_value(json!(true)).unwrap(); + assert_eq!(config, UserGlobalCacheConfig::Bool(true)); + let resolved = ResolvedGlobalCacheConfig::resolve_from(Some(&config)); + assert!(resolved.scripts); + assert!(resolved.tasks); + } + + #[test] + fn test_global_cache_bool_false() { + let config: UserGlobalCacheConfig = serde_json::from_value(json!(false)).unwrap(); + assert_eq!(config, UserGlobalCacheConfig::Bool(false)); + let resolved = ResolvedGlobalCacheConfig::resolve_from(Some(&config)); + assert!(!resolved.scripts); + assert!(!resolved.tasks); + } + + #[test] + fn test_global_cache_detailed_scripts_only() { + let config: UserGlobalCacheConfig = + serde_json::from_value(json!({ "scripts": true })).unwrap(); + let resolved = ResolvedGlobalCacheConfig::resolve_from(Some(&config)); + assert!(resolved.scripts); + assert!(resolved.tasks); // defaults to true + } + + #[test] + fn test_global_cache_detailed_tasks_false() { + let config: UserGlobalCacheConfig = + serde_json::from_value(json!({ "tasks": false })).unwrap(); + let resolved = ResolvedGlobalCacheConfig::resolve_from(Some(&config)); + assert!(!resolved.scripts); // defaults to false + assert!(!resolved.tasks); + } + + #[test] + fn test_global_cache_detailed_both() { + let config: UserGlobalCacheConfig = + serde_json::from_value(json!({ "scripts": true, "tasks": false })).unwrap(); + let resolved = ResolvedGlobalCacheConfig::resolve_from(Some(&config)); + assert!(resolved.scripts); + assert!(!resolved.tasks); + } + + #[test] + fn test_global_cache_none_defaults() { + let resolved = ResolvedGlobalCacheConfig::resolve_from(None); + assert!(!resolved.scripts); // defaults to false + assert!(resolved.tasks); // defaults to true + } + + #[test] + fn test_global_cache_detailed_unknown_field() { + assert!( + serde_json::from_value::(json!({ "unknown": true })).is_err() + ); + } } diff --git a/crates/vite_task_graph/src/lib.rs b/crates/vite_task_graph/src/lib.rs index 0a75ae1a..d09e7fe5 100644 --- a/crates/vite_task_graph/src/lib.rs +++ b/crates/vite_task_graph/src/lib.rs @@ -98,10 +98,8 @@ pub enum TaskGraphLoadError { error: SpecifierLookupError, }, - #[error( - "`cacheScripts` can only be set in the workspace root config, but found in {package_path}" - )] - CacheScriptsInNonRootPackage { package_path: Arc }, + #[error("`cache` can only be set in the workspace root config, but found in {package_path}")] + CacheInNonRootPackage { package_path: Arc }, } /// Error when looking up a task by its specifier. @@ -179,7 +177,7 @@ impl IndexedTaskGraph { /// /// Returns [`TaskGraphLoadError`] if the package graph fails to load, a config file /// cannot be read, a task config cannot be resolved, a dependency specifier is invalid, - /// or `cacheScripts` is set in a non-root package. + /// or `cache` is set in a non-root package. #[tracing::instrument(level = "debug", skip_all)] #[expect( clippy::too_many_lines, @@ -204,8 +202,8 @@ impl IndexedTaskGraph { let mut node_indices_by_task_id: FxHashMap = FxHashMap::with_capacity_and_hasher(task_graph.node_count(), FxBuildHasher); - // First pass: load all configs, extract cacheScripts from root, validate - let mut cache_scripts = false; // Default: disabled + // First pass: load all configs, extract root cache config, validate + let mut root_cache = None; let mut package_configs: Vec<(PackageNodeIndex, Arc, UserRunConfig)> = Vec::with_capacity(package_graph.node_count()); @@ -223,11 +221,11 @@ impl IndexedTaskGraph { })? .unwrap_or_default(); - if let Some(current_cache_scripts) = user_config.cache_scripts { + if let Some(cache) = user_config.cache { if is_workspace_root { - cache_scripts = current_cache_scripts; + root_cache = Some(cache); } else { - return Err(TaskGraphLoadError::CacheScriptsInNonRootPackage { + return Err(TaskGraphLoadError::CacheInNonRootPackage { package_path: package_dir.clone(), }); } @@ -236,7 +234,11 @@ impl IndexedTaskGraph { package_configs.push((package_index, package_dir, user_config)); } - // Second pass: create task nodes using cache_scripts value + let resolved_cache = config::ResolvedGlobalCacheConfig::resolve_from(root_cache.as_ref()); + let cache_scripts = resolved_cache.scripts; + let cache_tasks = resolved_cache.tasks; + + // Second pass: create task nodes using resolved cache config for (package_index, package_dir, user_config) in package_configs { let package = &package_graph[package_index]; @@ -248,7 +250,11 @@ impl IndexedTaskGraph { .map(|(name, value)| (name.as_str(), value.as_str())) .collect(); - for (task_name, task_user_config) in user_config.tasks.unwrap_or_default() { + for (task_name, mut task_user_config) in user_config.tasks.unwrap_or_default() { + // Apply cache.tasks kill switch: when false, override all tasks to disable caching + if !cache_tasks { + task_user_config.options.cache_config = config::UserCacheConfig::disabled(); + } // 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()); diff --git a/crates/vite_task_plan/src/plan.rs b/crates/vite_task_plan/src/plan.rs index 56841017..0d95dad3 100644 --- a/crates/vite_task_plan/src/plan.rs +++ b/crates/vite_task_plan/src/plan.rs @@ -312,7 +312,7 @@ pub enum ParentCacheConfig { /// The synthetic task uses its own default cache configuration. None, - /// Parent task has caching disabled (`cache: false` or `cacheScripts` not enabled). + /// Parent task has caching disabled (`cache: false` or `cache.scripts` not enabled). /// The synthetic task should also have caching disabled. Disabled, 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } 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 index e9f7182a..908833e0 100644 --- 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 @@ -1,4 +1,4 @@ { // Enables caching for all package.json scripts in the workspace. - "cacheScripts": true + "cache": { "scripts": true } } 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } 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 index 0efde8af..8006fe4f 100644 --- 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 @@ -3,4 +3,4 @@ source: crates/vite_task_plan/tests/plan_snapshots/main.rs expression: err_str.as_ref() 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 +`cache` 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-sharing/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-sharing/vite-task.json index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-subcommand/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-subcommand/vite-task.json index 1d0fe9f2..d548edfa 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-subcommand/vite-task.json +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-subcommand/vite-task.json @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/package.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/package.json new file mode 100644 index 00000000..877751fb --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/package.json @@ -0,0 +1,7 @@ +{ + "name": "@test/cache-tasks-disabled", + "scripts": { + "build": "echo building", + "test": "echo testing" + } +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/task graph.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/task graph.snap new file mode 100644 index 00000000..781d1cbf --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/snapshots/task graph.snap @@ -0,0 +1,70 @@ +--- +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-tasks-disabled +--- +[ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/cache-tasks-disabled", + "task_name": "build", + "package_path": "/" + }, + "resolved_config": { + "command": "echo building", + "resolved_options": { + "cwd": "/", + "cache_config": null + } + } + }, + "neighbors": [] + }, + { + "key": [ + "/", + "deploy" + ], + "node": { + "task_display": { + "package_name": "@test/cache-tasks-disabled", + "task_name": "deploy", + "package_path": "/" + }, + "resolved_config": { + "command": "echo deploying", + "resolved_options": { + "cwd": "/", + "cache_config": null + } + } + }, + "neighbors": [] + }, + { + "key": [ + "/", + "test" + ], + "node": { + "task_display": { + "package_name": "@test/cache-tasks-disabled", + "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-tasks-disabled/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/vite-task.json new file mode 100644 index 00000000..eb7bf948 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-tasks-disabled/vite-task.json @@ -0,0 +1,10 @@ +{ + "cache": { "tasks": false }, + "tasks": { + "build": {}, + "deploy": { + "command": "echo deploying", + "cache": true + } + } +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/package.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/package.json new file mode 100644 index 00000000..ae0f53ab --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/package.json @@ -0,0 +1,7 @@ +{ + "name": "@test/cache-true-no-force-enable", + "scripts": { + "build": "echo building", + "test": "echo testing" + } +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/snapshots/task graph.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/snapshots/task graph.snap new file mode 100644 index 00000000..a62b5101 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/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-true-no-force-enable +--- +[ + { + "key": [ + "/", + "build" + ], + "node": { + "task_display": { + "package_name": "@test/cache-true-no-force-enable", + "task_name": "build", + "package_path": "/" + }, + "resolved_config": { + "command": "echo building", + "resolved_options": { + "cwd": "/", + "cache_config": null + } + } + }, + "neighbors": [] + }, + { + "key": [ + "/", + "deploy" + ], + "node": { + "task_display": { + "package_name": "@test/cache-true-no-force-enable", + "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-true-no-force-enable", + "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-true-no-force-enable/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/vite-task.json new file mode 100644 index 00000000..b1e5d424 --- /dev/null +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cache-true-no-force-enable/vite-task.json @@ -0,0 +1,11 @@ +{ + "cache": true, + "tasks": { + "build": { + "cache": false + }, + "deploy": { + "command": "echo deploying" + } + } +} diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd-in-scripts/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd-in-scripts/vite-task.json index 1d0fe9f2..d548edfa 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd-in-scripts/vite-task.json +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/cd-in-scripts/vite-task.json @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": 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 index e9f7182a..a6d6c501 100644 --- 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 @@ -1,4 +1,4 @@ { // Enables caching for all package.json scripts in the workspace. - "cacheScripts": true + "cache": true } 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/filter-workspace/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/filter-workspace/vite-task.json index 1d0fe9f2..d548edfa 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/filter-workspace/vite-task.json +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/filter-workspace/vite-task.json @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/fingerprint-ignore-test/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/fingerprint-ignore-test/vite-task.json index f3583872..f3540d91 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/fingerprint-ignore-test/vite-task.json +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/fingerprint-ignore-test/vite-task.json @@ -1,5 +1,5 @@ { - "cacheScripts": true, + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots.toml b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots.toml index 5184b7f4..8b02ccf2 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots.toml +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots.toml @@ -1,5 +1,5 @@ [[plan]] -name = "script without cacheScripts defaults to no cache" +name = "script without cache.scripts defaults to no cache" args = ["run", "lint"] [[plan]] diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - script without cacheScripts defaults to no cache.snap b/crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - script without cache.scripts defaults to no cache.snap similarity index 100% rename from crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - script without cacheScripts defaults to no cache.snap rename to crates/vite_task_plan/tests/plan_snapshots/fixtures/synthetic-cache-disabled/snapshots/query - script without cache.scripts defaults to no cache.snap 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 index 1d0fe9f2..d548edfa 100644 --- 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 @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } diff --git a/crates/vite_task_plan/tests/plan_snapshots/fixtures/vpr-shorthand/vite-task.json b/crates/vite_task_plan/tests/plan_snapshots/fixtures/vpr-shorthand/vite-task.json index 1d0fe9f2..d548edfa 100644 --- a/crates/vite_task_plan/tests/plan_snapshots/fixtures/vpr-shorthand/vite-task.json +++ b/crates/vite_task_plan/tests/plan_snapshots/fixtures/vpr-shorthand/vite-task.json @@ -1,3 +1,3 @@ { - "cacheScripts": true + "cache": true } 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 index e79ab80a..942c99fe 100644 --- 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 @@ -1,7 +1,7 @@ { // This workspace root has no package.json — only pnpm-workspace.yaml. // vite-task.json should still be loaded and applied. - "cacheScripts": true, + "cache": true, "tasks": { "deploy": { "command": "echo deploying workspace"