Skip to content

ci: cache package builds with Vite+ across GitHub Actions runs - #3

Draft
wan9chi wants to merge 5 commits into
mainfrom
agent/vite-plus-package-build-cache
Draft

ci: cache package builds with Vite+ across GitHub Actions runs#3
wan9chi wants to merge 5 commits into
mainfrom
agent/vite-plus-package-build-cache

Conversation

@wan9chi

@wan9chi wan9chi commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Motivation

pnpm build runs 25 tasks across 20 packages, almost all plain tsdown. Every
CI job that needs built packages — typecheck, lint — pays for that build in full,
even when nothing it depends on changed.

Vite+ can cache those task results, but until now this workspace could not use it
without hand-written input/output globs for each package: a task that reads
its own generated files had its fingerprint change on every run, so it could
never hit. voidzero-dev/vite-task#571
fixes that classification, and this PR wires it up so CI reuses the cache across
runs.

Locally, with no cache configuration at all:

  • second run: 25/25 cache hit (100%), 33.77s saved
  • after deleting all 20 packages/*/dist directories: 24/25 hit, 1432 files
    restored from the output archives

The single miss is correct rather than a gap: removing packages/core/dist also
empties node_modules/emdash/dist, which is a real input to the dependent task.

What is here

  • ci: reuse the Vite+ task cache across runs — restores and saves
    node_modules/.vite/task-cache in the typecheck and lint jobs. Restored after
    install, because installing recreates node_modules. Task inputs stay out of
    the Actions key on purpose: Vite Task fingerprints them, and putting them in
    the key would skip useful restores before it can decide what still hits. The
    two jobs use separate key prefixes because they run in parallel and would
    otherwise race to save the same immutable key.
  • chore: test the Vite+ task-tracking preview buildtemporary, not for
    merge.
    Pins vite-plus to the preview build of
    voidzero-dev/vite-plus#2260
    so CI runs the fix. Bridge builds have no provenance attestation and are
    published minutes before use, so they need exemptions from both trustPolicy
    and minimumReleaseAge. Reverting the .npmrc registry, the version pin and
    the two pnpm-workspace.yaml exclusions returns to the published release.

Measured in CI

Cross-run reuse is still experimental upstream, so it was measured here rather
than assumed. Three runs on this branch, Typecheck job:

run change Vite Task job time
1 first run, no cache to restore 0/25 hit 5m24s
2 doc-only, unrelated to any build 22/25 hit, 122.74s saved 3m08s
3 one leaf plugin's source 21/25 hit, 116.20s saved 3m26s

Run 1 logged Cache not found, then Cache saved with key: vite-task-typecheck-Linux-X64-<run-id>-1; run 2 restored that exact key through
the prefix. Lint went 3m50s to 1m31s over the same runs.

Run 3's extra miss is precisely the package that changed:
packages/plugins/audit-log ... cache miss: 'packages/plugins/audit-log/src/plugin.ts' modified.
Nothing else rebuilt.

Three tasks miss on every run, and neither is caused by the tracking change:

  • registry-lexicons build:lexicons and build:types read
    node_modules/.pnpm-workspace-state-v1.json, which pnpm rewrites on each
    install, so the fingerprint cannot survive a fresh checkout. This is the case
    upstream documents under
    When To Add Manual Config
    and wants a manual input exclusion.
  • packages/core tsdown reads node_modules/emdash/dist/index.d.mts, which is
    its own output seen through the node_modules/emdash symlink. On a fresh
    checkout that path does not exist yet, so the input genuinely differs.

Worth fixing before this is relied on, but both are workspace-level tracking
config rather than blockers for the cache wiring itself.

wan9chi and others added 4 commits July 13, 2026 15:15
`pnpm build` runs through `vp run`, so its task results can be restored
from a previous run instead of rebuilt. Restored after install because
installing recreates `node_modules`, which is where the task cache lives.

Cache entries are immutable, so the primary key carries the run id and
attempt while the restore prefix picks up the newest entry for the same
runner. Task inputs are deliberately absent from the key: Vite Task
fingerprints them itself, and putting them in the key would skip useful
restores before it can decide which tasks still hit.

Typecheck and lint keep separate key prefixes because they run in
parallel and would otherwise race to save the same immutable key.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
TEMPORARY, not for merge. Pins vite-plus to the preview build of
voidzero-dev/vite-plus#2260, which carries the automatic tracking change
in voidzero-dev/vite-task#571, so CI exercises it on this workspace.

The bridge registry is what makes the same version resolve in CI, so it
goes in .npmrc rather than being passed on the command line. Bridge builds
carry no provenance attestation and are published minutes before use, so
they need exemptions from both the trust policy and the release-age
cooldown.

Revert all four pieces to return to the published release: the .npmrc
registry, the version pin, and the two pnpm-workspace exclusions.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Scope check

This PR changes 5,676 lines across 6 files. Large PRs are harder to review and more likely to be closed without review.

If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs.

See CONTRIBUTING.md for contribution guidelines.

@github-actions

Copy link
Copy Markdown


Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.


I have read the CLA Document and I hereby sign the CLA


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@github-actions

Copy link
Copy Markdown

PR template validation failed

Please fix the following issues by editing your PR description:

  • This PR does not use the required PR template. Please edit the description to use the PR template. Copy it into your PR description and fill out all sections.

See CONTRIBUTING.md for the full contribution policy.

@wan9chi
wan9chi force-pushed the agent/vite-plus-package-build-cache branch from 11000f7 to 72338d3 Compare July 26, 2026 16:19
Vite Task's DEFAULT_CONCURRENCY_LIMIT is already 4, so the flag set the
value it would have used anyway. Measured on this workspace: with the flag,
without it, and at --concurrency-limit=12 all give a 16-18s cold build and
a 2.6s warm build at 25/25 cache hits. Concurrency is per graph level and
this graph is deep rather than wide, so raising the limit changes nothing.

A limit does still matter, just not this one: --parallel removes it
entirely and reproducibly drops to 18/25 hits, because sibling tasks write
into directories another task is reading and the reader's fingerprint picks
up files that were absent when its entry was stored.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@wan9chi
wan9chi force-pushed the agent/vite-plus-package-build-cache branch from 6f44a7a to 48225c2 Compare July 27, 2026 01:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant