Skip to content

Commit 496210c

Browse files
branchseerclaude
andcommitted
refactor(config): rename ResolvedInputConfig to ResolvedGlobConfig and add output field
Rename `ResolvedInputConfig` to `ResolvedGlobConfig` since the struct is now shared by both input and output config. Add `output` field to `EnabledCacheConfig` with the same type as `input` (`Option<UserInputsConfig>`), defaulting to auto-detection. Add `output_config` to `CacheConfig` and resolve it via the shared `ResolvedGlobConfig::from_user_config()`. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 076cef4 commit 496210c

3 files changed

Lines changed: 57 additions & 20 deletions

File tree

crates/vite_task_graph/run-config.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,18 @@ untrackedEnv?: Array<string>,
5353
* - `{auto: true}` enables automatic file tracking
5454
* - Negative patterns (e.g. `"!dist/**"`) exclude matched files
5555
*/
56-
input?: Array<string | GlobWithBase | AutoInput>, } | {
56+
input?: Array<string | GlobWithBase | AutoInput>,
57+
/**
58+
* Output files to archive and restore on cache hit.
59+
*
60+
* - Omitted: automatically tracks which files the task writes
61+
* - `[]` (empty): disables output restoration entirely
62+
* - Glob patterns (e.g. `"dist/**"`) select specific output files, relative to the package directory
63+
* - `{pattern: "...", base: "workspace" | "package"}` specifies a glob with an explicit base directory
64+
* - `{auto: true}` enables automatic file tracking
65+
* - Negative patterns (e.g. `"!dist/cache/**"`) exclude matched files
66+
*/
67+
output?: Array<string | GlobWithBase | AutoInput>, } | {
5768
/**
5869
* Whether to cache the task
5970
*/

crates/vite_task_graph/src/config/mod.rs

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,18 @@ impl ResolvedTaskOptions {
6969
enabled_cache_config.untracked_env.unwrap_or_default().into_iter().collect();
7070
untracked_env.extend(DEFAULT_UNTRACKED_ENV.iter().copied().map(Str::from));
7171

72-
let input_config = ResolvedInputConfig::from_user_config(
72+
let input_config = ResolvedGlobConfig::from_user_config(
7373
enabled_cache_config.input.as_ref(),
7474
dir,
7575
workspace_root,
7676
)?;
7777

78+
let output_config = ResolvedGlobConfig::from_user_config(
79+
enabled_cache_config.output.as_ref(),
80+
dir,
81+
workspace_root,
82+
)?;
83+
7884
Some(CacheConfig {
7985
env_config: EnvConfig {
8086
fingerprinted_envs: enabled_cache_config
@@ -84,6 +90,7 @@ impl ResolvedTaskOptions {
8490
untracked_env,
8591
},
8692
input_config,
93+
output_config,
8794
})
8895
}
8996
};
@@ -92,9 +99,14 @@ impl ResolvedTaskOptions {
9299
}
93100

94101
#[derive(Debug, Clone, Serialize)]
102+
#[expect(
103+
clippy::struct_field_names,
104+
reason = "env_config, input_config, output_config are distinct config categories, not a naming smell"
105+
)]
95106
pub struct CacheConfig {
96107
pub env_config: EnvConfig,
97-
pub input_config: ResolvedInputConfig,
108+
pub input_config: ResolvedGlobConfig,
109+
pub output_config: ResolvedGlobConfig,
98110
}
99111

100112
/// Resolved input configuration for cache fingerprinting.
@@ -104,7 +116,7 @@ pub struct CacheConfig {
104116
/// - `positive_globs`: Glob patterns for files to include (without `!` prefix)
105117
/// - `negative_globs`: Glob patterns for files to exclude (without `!` prefix)
106118
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Encode, Decode)]
107-
pub struct ResolvedInputConfig {
119+
pub struct ResolvedGlobConfig {
108120
/// Whether automatic file tracking is enabled
109121
pub includes_auto: bool,
110122

@@ -117,7 +129,7 @@ pub struct ResolvedInputConfig {
117129
pub negative_globs: BTreeSet<Str>,
118130
}
119131

120-
impl ResolvedInputConfig {
132+
impl ResolvedGlobConfig {
121133
/// Default configuration: auto-inference enabled, no explicit patterns
122134
#[must_use]
123135
pub const fn default_auto() -> Self {
@@ -425,7 +437,7 @@ mod tests {
425437

426438
#[test]
427439
fn test_resolved_input_config_default_auto() {
428-
let config = ResolvedInputConfig::default_auto();
440+
let config = ResolvedGlobConfig::default_auto();
429441
assert!(config.includes_auto);
430442
assert!(config.positive_globs.is_empty());
431443
assert!(config.negative_globs.is_empty());
@@ -435,7 +447,7 @@ mod tests {
435447
fn test_resolved_input_config_from_none() {
436448
let (pkg, ws) = test_paths();
437449
// None means default to auto-inference
438-
let config = ResolvedInputConfig::from_user_config(None, &pkg, &ws).unwrap();
450+
let config = ResolvedGlobConfig::from_user_config(None, &pkg, &ws).unwrap();
439451
assert!(config.includes_auto);
440452
assert!(config.positive_globs.is_empty());
441453
assert!(config.negative_globs.is_empty());
@@ -446,7 +458,7 @@ mod tests {
446458
let (pkg, ws) = test_paths();
447459
// Empty array means no inputs, inference disabled
448460
let user_inputs = vec![];
449-
let config = ResolvedInputConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
461+
let config = ResolvedGlobConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
450462
assert!(!config.includes_auto);
451463
assert!(config.positive_globs.is_empty());
452464
assert!(config.negative_globs.is_empty());
@@ -456,7 +468,7 @@ mod tests {
456468
fn test_resolved_input_config_auto_only() {
457469
let (pkg, ws) = test_paths();
458470
let user_inputs = vec![UserInputEntry::Auto(AutoInput { auto: true })];
459-
let config = ResolvedInputConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
471+
let config = ResolvedGlobConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
460472
assert!(config.includes_auto);
461473
assert!(config.positive_globs.is_empty());
462474
assert!(config.negative_globs.is_empty());
@@ -466,7 +478,7 @@ mod tests {
466478
fn test_resolved_input_config_auto_false_ignored() {
467479
let (pkg, ws) = test_paths();
468480
let user_inputs = vec![UserInputEntry::Auto(AutoInput { auto: false })];
469-
let config = ResolvedInputConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
481+
let config = ResolvedGlobConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
470482
assert!(!config.includes_auto);
471483
assert!(config.positive_globs.is_empty());
472484
assert!(config.negative_globs.is_empty());
@@ -480,7 +492,7 @@ mod tests {
480492
UserInputEntry::Glob("src/**/*.ts".into()),
481493
UserInputEntry::Glob("package.json".into()),
482494
];
483-
let config = ResolvedInputConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
495+
let config = ResolvedGlobConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
484496
assert!(!config.includes_auto);
485497
assert_eq!(config.positive_globs.len(), 2);
486498
// Globs should now be workspace-root-relative
@@ -496,7 +508,7 @@ mod tests {
496508
UserInputEntry::Glob("src/**".into()),
497509
UserInputEntry::Glob("!src/**/*.test.ts".into()),
498510
];
499-
let config = ResolvedInputConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
511+
let config = ResolvedGlobConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
500512
assert!(!config.includes_auto);
501513
assert_eq!(config.positive_globs.len(), 1);
502514
assert!(config.positive_globs.contains("packages/my-pkg/src/**"));
@@ -512,7 +524,7 @@ mod tests {
512524
UserInputEntry::Auto(AutoInput { auto: true }),
513525
UserInputEntry::Glob("!node_modules/**".into()),
514526
];
515-
let config = ResolvedInputConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
527+
let config = ResolvedGlobConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
516528
assert!(config.includes_auto);
517529
assert_eq!(config.positive_globs.len(), 1);
518530
assert!(config.positive_globs.contains("packages/my-pkg/package.json"));
@@ -528,15 +540,15 @@ mod tests {
528540
UserInputEntry::Glob("src/**/*.ts".into()),
529541
UserInputEntry::Auto(AutoInput { auto: true }),
530542
];
531-
let config = ResolvedInputConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
543+
let config = ResolvedGlobConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
532544
assert!(config.includes_auto);
533545
}
534546

535547
#[test]
536548
fn test_resolved_input_config_dotdot_resolution() {
537549
let (pkg, ws) = test_paths();
538550
let user_inputs = vec![UserInputEntry::Glob("../shared/src/**".into())];
539-
let config = ResolvedInputConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
551+
let config = ResolvedGlobConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
540552
assert_eq!(config.positive_globs.len(), 1);
541553
assert!(
542554
config.positive_globs.contains("packages/shared/src/**"),
@@ -549,7 +561,7 @@ mod tests {
549561
fn test_resolved_input_config_outside_workspace_error() {
550562
let (pkg, ws) = test_paths();
551563
let user_inputs = vec![UserInputEntry::Glob("../../../outside/**".into())];
552-
let result = ResolvedInputConfig::from_user_config(Some(&user_inputs), &pkg, &ws);
564+
let result = ResolvedGlobConfig::from_user_config(Some(&user_inputs), &pkg, &ws);
553565
assert!(result.is_err());
554566
assert!(matches!(result.unwrap_err(), ResolveTaskConfigError::GlobOutsideWorkspace { .. }));
555567
}
@@ -561,7 +573,7 @@ mod tests {
561573
pattern: "configs/tsconfig.json".into(),
562574
base: InputBase::Workspace,
563575
})];
564-
let config = ResolvedInputConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
576+
let config = ResolvedGlobConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
565577
assert!(!config.includes_auto);
566578
assert_eq!(config.positive_globs.len(), 1);
567579
// Workspace-base: should NOT have the package prefix
@@ -579,7 +591,7 @@ mod tests {
579591
pattern: "!dist/**".into(),
580592
base: InputBase::Workspace,
581593
})];
582-
let config = ResolvedInputConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
594+
let config = ResolvedGlobConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
583595
assert_eq!(config.negative_globs.len(), 1);
584596
assert!(
585597
config.negative_globs.contains("dist/**"),
@@ -596,7 +608,7 @@ mod tests {
596608
pattern: "src/**/*.ts".into(),
597609
base: InputBase::Package,
598610
})];
599-
let config = ResolvedInputConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
611+
let config = ResolvedGlobConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
600612
assert_eq!(config.positive_globs.len(), 1);
601613
assert!(
602614
config.positive_globs.contains("packages/my-pkg/src/**/*.ts"),
@@ -620,7 +632,7 @@ mod tests {
620632
base: InputBase::Workspace,
621633
}),
622634
];
623-
let config = ResolvedInputConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
635+
let config = ResolvedGlobConfig::from_user_config(Some(&user_inputs), &pkg, &ws).unwrap();
624636
assert!(config.includes_auto);
625637
assert_eq!(config.positive_globs.len(), 2);
626638
assert!(config.positive_globs.contains("packages/my-pkg/src/**"));

crates/vite_task_graph/src/config/user.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,18 @@ pub struct EnabledCacheConfig {
125125
#[serde(default)]
126126
#[cfg_attr(all(test, not(clippy)), ts(inline))]
127127
pub input: Option<UserInputsConfig>,
128+
129+
/// Output files to archive and restore on cache hit.
130+
///
131+
/// - Omitted: automatically tracks which files the task writes
132+
/// - `[]` (empty): disables output restoration entirely
133+
/// - Glob patterns (e.g. `"dist/**"`) select specific output files, relative to the package directory
134+
/// - `{pattern: "...", base: "workspace" | "package"}` specifies a glob with an explicit base directory
135+
/// - `{auto: true}` enables automatic file tracking
136+
/// - Negative patterns (e.g. `"!dist/cache/**"`) exclude matched files
137+
#[serde(default)]
138+
#[cfg_attr(all(test, not(clippy)), ts(inline))]
139+
pub output: Option<UserInputsConfig>,
128140
}
129141

130142
/// Options for user-defined tasks in `vite.config.*`, excluding the command.
@@ -160,6 +172,7 @@ impl Default for UserTaskOptions {
160172
env: None,
161173
untracked_env: None,
162174
input: None,
175+
output: None,
163176
},
164177
},
165178
}
@@ -428,6 +441,7 @@ mod tests {
428441
env: Some(std::iter::once("NODE_ENV".into()).collect()),
429442
untracked_env: Some(std::iter::once("FOO".into()).collect()),
430443
input: None,
444+
output: None,
431445
}
432446
},
433447
);

0 commit comments

Comments
 (0)