Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions packages/cli/binding/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,21 @@ fn build_pack_cache_inputs() -> Vec<UserInputEntry> {
]
}

/// Cache input entries for the check command.
/// The vp check subprocess is a full vp CLI process (not resolved to a binary like
/// build/lint/fmt), so it accesses additional directories that must be excluded:
/// - `.vite-temp`: config compilation cache, read+written during vp CLI startup
/// - `.vite/task-cache`: task runner state files that change after each run
fn check_cache_inputs() -> Vec<UserInputEntry> {
vec![
UserInputEntry::Auto(AutoInput { auto: true }),
exclude_glob("!node_modules/.vite-temp/**", InputBase::Workspace),
exclude_glob("!node_modules/.vite-temp/**", InputBase::Package),
exclude_glob("!node_modules/.vite/task-cache/**", InputBase::Workspace),
exclude_glob("!node_modules/.vite/task-cache/**", InputBase::Package),
]
}

fn merge_resolved_envs(
envs: &Arc<FxHashMap<Arc<OsStr>, Arc<OsStr>>>,
resolved_envs: Vec<(String, String)>,
Expand Down Expand Up @@ -587,10 +602,14 @@ impl CommandHandler for VitePlusCommandHandler {
};
match cli_args {
CLIArgs::Synthesizable(SynthesizableSubcommand::Check { .. }) => {
// Check is a composite command — run as a subprocess in task scripts
Ok(HandledCommand::Synthesized(
command.to_synthetic_plan_request(UserCacheConfig::disabled()),
))
// Check is a composite command (fmt + lint) — run as a subprocess in task scripts
Ok(HandledCommand::Synthesized(command.to_synthetic_plan_request(
UserCacheConfig::with_config(EnabledCacheConfig {
env: Some(Box::new([Str::from("OXLINT_TSGOLINT_PATH")])),
untracked_env: None,
input: Some(check_cache_inputs()),
}),
)))
}
CLIArgs::Synthesizable(subcmd) => {
let resolved =
Expand Down
7 changes: 7 additions & 0 deletions packages/cli/snap-tests/check-cache-disabled/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "check-cache-disabled-test",
"type": "module",
"scripts": {
"check": "vp check"
}
}
5 changes: 5 additions & 0 deletions packages/cli/snap-tests/check-cache-disabled/snap.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
> vp run check # vp check should have cache disabled without run.cache
$ vp check ⊘ cache disabled
pass: All 3 files are correctly formatted (<variable>ms, <variable> threads)
pass: Found no warnings or lint errors in 1 file (<variable>ms, <variable> threads)

5 changes: 5 additions & 0 deletions packages/cli/snap-tests/check-cache-disabled/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function hello() {
return "hello";
}

export { hello };
3 changes: 3 additions & 0 deletions packages/cli/snap-tests/check-cache-disabled/steps.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"commands": ["vp run check # vp check should have cache disabled without run.cache"]
}
7 changes: 7 additions & 0 deletions packages/cli/snap-tests/check-cache-enabled/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "check-cache-enabled-test",
"type": "module",
"scripts": {
"check": "vp check"
}
}
20 changes: 20 additions & 0 deletions packages/cli/snap-tests/check-cache-enabled/snap.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
> vp run check # first run should be cache miss
$ vp check
pass: All 4 files are correctly formatted (<variable>ms, <variable> threads)
pass: Found no warnings or lint errors in 2 files (<variable>ms, <variable> threads)


> vp run check # second run should be cache hit
$ vp check ◉ cache hit, replaying
pass: All 4 files are correctly formatted (<variable>ms, <variable> threads)
pass: Found no warnings or lint errors in 2 files (<variable>ms, <variable> threads)

---
vp run: cache hit, <variable>ms saved.

> echo 'export const foo = 1;' > src/foo.js
> vp run check # third run should be cache miss after new file added
$ vp check ○ cache miss: 'foo.js' added in 'src', executing
pass: All 5 files are correctly formatted (<variable>ms, <variable> threads)
pass: Found no warnings or lint errors in 3 files (<variable>ms, <variable> threads)

5 changes: 5 additions & 0 deletions packages/cli/snap-tests/check-cache-enabled/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function hello() {
return "hello";
}

export { hello };
9 changes: 9 additions & 0 deletions packages/cli/snap-tests/check-cache-enabled/steps.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"ignoredPlatforms": ["win32"],
"commands": [
"vp run check # first run should be cache miss",
"vp run check # second run should be cache hit",
"echo 'export const foo = 1;' > src/foo.js",
"vp run check # third run should be cache miss after new file added"
]
}
5 changes: 5 additions & 0 deletions packages/cli/snap-tests/check-cache-enabled/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
run: {
cache: true,
},
};
46 changes: 46 additions & 0 deletions rfcs/check-command.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,45 @@ With `vp check`, the monorepo template's "ready" script simplifies to:
"ready": "vp check && vp run -r test && vp run -r build"
```

## Caching

When `vp check` is used as a package.json script (e.g., `"check": "vp check"`) and executed via `vp run check`, it supports task runner caching like other synthesized commands (`vp build`, `vp lint`, `vp fmt`).

### Configuration

Enable caching in `vite.config.ts`:

```ts
export default {
run: {
cache: true,
},
};
```

With caching enabled, the second `vp run check` replays cached output when inputs haven't changed:

```
$ vp check ◉ cache hit, replaying
pass: All 4 files are correctly formatted (105ms, 16 threads)
pass: Found no warnings or lint errors in 2 files (452ms, 16 threads)
```

### Cache key

The check command's cache fingerprint includes:

- **Environment variable:** `OXLINT_TSGOLINT_PATH` (affects lint behavior)
- **Input files:** Auto-tracked via fspy, excluding:
- `node_modules/.vite-temp/**` — config compilation cache (read+written by the vp CLI subprocess)
- `node_modules/.vite/task-cache/**` — task runner state files that change after each run

These exclusions are shared with other synthesized commands via `base_cache_inputs()` in `cli.rs`.

### How it differs from `vp fmt` / `vp lint`

When `vp fmt` or `vp lint` appear in task scripts, the command handler resolves them to their underlying binaries (e.g., `node path/to/oxfmt.mjs`). The `vp check` command is different — it runs as a full `vp check` subprocess because it's a composite command that orchestrates both fmt and lint internally. This means the `vp` CLI process itself is tracked by fspy, which is why the `.vite-temp` and `.vite/task-cache` exclusions are necessary.

## Comparison with Other Tools

| Tool | Scope |
Expand Down Expand Up @@ -252,4 +291,11 @@ packages/cli/snap-tests/check-no-fmt/
package.json
steps.json # { "steps": [{ "command": "vp check --no-fmt" }] }
snap.txt # Only lint runs

packages/cli/snap-tests/check-cache-enabled/
package.json # { "scripts": { "check": "vp check" } }
vite.config.ts # { run: { cache: true } }
steps.json # Runs vp run check twice, expects cache hit on second run
src/index.js
snap.txt
```
Loading