Skip to content

perf(scripts): cache registry responses so --check runs in 0.05s instead of 29s - #3062

Merged
os-zhuang merged 1 commit into
mainfrom
claude/shadcn-check-cache
Jul 30, 2026
Merged

perf(scripts): cache registry responses so --check runs in 0.05s instead of 29s#3062
os-zhuang merged 1 commit into
mainfrom
claude/shadcn-check-cache

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

--check makes one HTTPS request per tracked component — 46 round trips for a run that is almost entirely I/O wait: 28.6s wall against 0.13s of user time. That's enough friction that nobody runs the status command, which rather defeats having one.

Result

wall registry
cold (empty cache) 26.86s 0 cached, 46 fetched
warm 0.05s 46 cached, 0 fetched
--no-cache 28.74s 0 cached, 46 fetched

Responses are cached under node_modules/.cache/shadcn-sync/, keyed by source URL, 60-minute TTL. That's the conventional home: already gitignored (verified with git check-ignore), and a clean install discards it — the right lifetime for a cache.

The load-bearing detail: reads only

allowCache gates reading, and only read-only commands pass it.

command reads cache? writes cache?
--check, --diff
--update, --update-all never

A stale --check is a slightly out-of-date status line. A stale --update would put hour-old code on disk under a message saying it's current. Writes still refresh the entry, so an update leaves the cache warm for the next check.

Proved it by poisoning the cache. Overwrote the cached button entry with // POISONED CACHE — this must never reach disk:

  • --check → reported button as 51 local line(s) … --update would refuse. It reads the cache, so it saw the poison. ✅
  • --update buttonignored the poison entirely, fetched live, wrote the real upstream content. Clean git tree, zero POISONED lines on disk, and the cache entry was write-refreshed (poison gone, fetchedAt 17s old). ✅

Failure modes are quiet by design

  • Missing / unreadable / corrupt entry → falls through to the network. Wrote not json at all {{{ into one file: 45 cached, 1 fetched, exit 0, 0 errors.
  • Cache directory unwritable → the write is swallowed; a cache is an optimisation and must never fail a run.
  • TTL expiry → aged every entry to 61 minutes: 0 cached, 46 fetched. ✅

Always says where the data came from

Registry: 46 cached, 0 fetched (cache TTL 60min — --no-cache to force live)

A run that returns in 50ms is otherwise indistinguishable from one that silently fetched nothing.

Verification

No changeset — tooling only.

🤖 Generated with Claude Code

…ead of 29s

`--check` makes one HTTPS request per tracked component — 46 round trips
for a run that is almost entirely I/O wait: 28.6s wall against 0.13s of
user time. That is enough friction that nobody runs the status command,
which rather defeats having one.

Responses are now cached under `node_modules/.cache/shadcn-sync/`, keyed
by source URL, with a 60-minute TTL:

  cold (empty cache)   26.86s   0 cached, 46 fetched
  warm                  0.05s  46 cached,  0 fetched
  --no-cache           28.74s   0 cached, 46 fetched

`node_modules/.cache/` is the conventional home: already gitignored
(verified via git check-ignore), and a clean install discards it, which
is the right lifetime for a cache.

The load-bearing detail is that `allowCache` gates READS only, and only
read-only commands pass it. `--check` and `--diff` may answer from cache;
`--update` and `--update-all` never do. A stale `--check` is a slightly
out-of-date status line, but a stale `--update` would put hour-old code
on disk under a message saying it is current. Writes still refresh the
entry, so an update leaves the cache warm for the next check.

Proved that split by poisoning the cached `button` entry:
`--check` reported button as 51-line modified — it reads the cache — while
`--update button` ignored the poison entirely, wrote the real upstream
content (clean tree, zero POISONED lines), and write-refreshed the entry.

Degradation is quiet by design: a missing, unreadable or corrupt entry
falls through to the network (garbage file → 45 cached, 1 fetched, exit
0), and a cache directory that cannot be written never fails the run.
Expiry verified by ageing every entry to 61 minutes — 0 cached, 46
fetched.

The summary always reports where the data came from. A run that returns
in 50ms is otherwise indistinguishable from one that silently fetched
nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectui Ignored Ignored Jul 30, 2026 3:01pm

Request Review

@os-zhuang
os-zhuang merged commit c41174a into main Jul 30, 2026
15 checks passed
@os-zhuang
os-zhuang deleted the claude/shadcn-check-cache branch July 30, 2026 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant