Skip to content

fix(cache): keep the local .cache root out of the user's git history - #3581

Merged
kojiwakayama merged 2 commits into
mainfrom
fix/dx-20260811-b2-27
Aug 11, 2026
Merged

kojiwakayama merged 2 commits into
mainfrom
fix/dx-20260811-b2-27

Conversation

@kojiwakayama

Copy link
Copy Markdown
Contributor

Found during a DX dogfood walk of the public docs (install → adopt into an existing project → veryfront dev).

Symptom

veryfront dev writes generated bundles into <project>/.cache and, on the "blank or existing project" adoption path documented in docs/getting-started/installation.md, nothing ever tells git to ignore them.

Reproduced against this tree with the real CLI: scaffold an app, replace its .gitignore with a typical pre-existing one (node_modules/, dist/, .env), git init, veryfront dev, load one page:

?? .cache/veryfront-mdx-esm/framework/vfmod-vf-framework-69317ee3-54d458af-7fb5feaf-761acd69.mjs
?? .cache/veryfront-mdx-esm/myapp/local-main/app/layout.13a96ac5.js
... (and the rest of .cache/)

git add -A there commits generated bundle artifacts.

Root cause

getDefaultCacheBaseDir() (src/utils/cache-dir.ts) resolves to join(cwd(), ".cache") outside production, so the cache root lives inside the user's repo. The only thing that ever ignores it is the .gitignore that veryfront init scaffolds (generateGitignoreContent, cli/utils/env-prompt.ts). That function's amend branch — the one used when a .gitignore already exists — adds only .env* and .veryfront/, never .cache/, and it is near-unreachable from init anyway (veryfront init . is rejected, and init over an existing directory refuses without --force). A project that adopts Veryfront never runs the scaffold path at all, so it gets no entry from anywhere. The published package has no install scripts either.

Fix

Write a .gitignore containing * inside the cache root, the way .vercel/ and .nx/cache/ do. That ignores the directory's contents and the marker itself no matter what the project's own .gitignore says, so it covers the scaffold path, the adopt path, and a custom VERYFRONT_CACHE_DIR with one mechanism instead of trying to edit a file the framework does not own.

  • ensureCacheDirIgnored() in src/utils/cache-dir.ts — best-effort (an unwritable cache root must not fail server startup) and it never overwrites an existing .gitignore.
  • Called from clearAllLocalCaches(), the documented "call this on server startup" hook, which is what dev, start, and serve all run before the first cache write.
  • Also relabels the scaffolded comment: .cache/ holds veryfront-mdx-esm/ and veryfront-http-bundle/, not the "Local AI model cache" it claimed.

Regression test

  • src/transforms/mdx/esm-module-loader/cache/index.test.ts — "marks the local cache root as ignored on startup". It lives next to clearAllLocalCaches because that is the startup seam the bug went through: the test drives the same function the dev server calls and asserts the cache root ends up self-ignoring. Confirmed failing before the fix (.gitignore absent), passing after.
  • src/utils/cache-dir.test.ts — two unit cases for ensureCacheDirIgnored: it writes the * marker, and it leaves a user-authored .gitignore alone.

Deno BDD throughout; no browser needed.

Verification

Reran the finding's command against the fixed tree in the same adopt-path sandbox. .cache/.gitignore is now present with *, and git status --porcelain -uall lists zero entries under .cache:

?? .gitignore
?? AGENTS.md
?? README.md
?? app/about/page.mdx
?? app/layout.tsx
?? app/page.tsx
?? package-lock.json
?? package.json
?? public/favicon.svg

deno test over src/utils, src/cache, src/transforms, cli/utils, src/modules/react-loader: 395 passed, 0 failed. The pre-push gate (fmt check + full unit suite) passed.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@kojiwakayama, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 24 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cb2b3355-35a2-4e46-8927-9f1ca01097eb

📥 Commits

Reviewing files that changed from the base of the PR and between 718355c and 73d7920.

📒 Files selected for processing (6)
  • cli/utils/env-prompt.test.ts
  • cli/utils/env-prompt.ts
  • src/transforms/mdx/esm-module-loader/cache/index.test.ts
  • src/transforms/mdx/esm-module-loader/cache/index.ts
  • src/utils/cache-dir.test.ts
  • src/utils/cache-dir.ts

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dc282494bf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/cache-dir.ts Outdated
Comment thread src/utils/cache-dir.ts Outdated
Outside production the cache root is `<project>/.cache`, so every dev
server run drops generated bundles into the user's project. `veryfront
init` scaffolds a .gitignore that lists `.cache/`, but a project that
adopted Veryfront into an existing tree keeps its own .gitignore and
never gets the entry — the generated .mjs files then show up as
untracked and `git add -A` commits them.

Write a `.gitignore` containing `*` inside the cache root on server
startup instead. It ignores the directory's contents and itself
regardless of what the project's own .gitignore says, so it works on the
scaffold path, the adopt path, and any custom VERYFRONT_CACHE_DIR. It is
best-effort and never overwrites an existing file.

Also relabel the scaffolded `.cache/` comment: the directory holds
`veryfront-mdx-esm/` and `veryfront-http-bundle/`, not AI models.
…m dash

Review follow-up:

- The generated `.cache/.gitignore` comment lands in the user's project, so
  it is public copy and must not contain an em dash (AGENTS.md public copy
  rules). Replace it with a comma.
- Write the marker through `createFileBytesExclusive` when the adapter
  exposes it, treating an already-exists error as success, so a `.gitignore`
  that appears between the `exists()` check and the write is not truncated.
  Adapters without the capability keep the plain write.
@kojiwakayama
kojiwakayama force-pushed the fix/dx-20260811-b2-27 branch from dc28249 to 73d7920 Compare August 11, 2026 10:20
@kojiwakayama
kojiwakayama added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit b859463 Aug 11, 2026
33 checks passed
@kojiwakayama
kojiwakayama deleted the fix/dx-20260811-b2-27 branch August 11, 2026 13:06
kojiwakayama added a commit that referenced this pull request Aug 12, 2026
Outside production the cache root is `<project>/.cache`, so `veryfront build`
drops generated bundles into the user's project. #3581 wrote a self-ignoring
`.cache/.gitignore` from `clearAllLocalCaches()`, which only `veryfront dev`,
`start`, and `serve` call, so the build path was left uncovered: a project that
adopted Veryfront into an existing tree still saw ten untracked `.mjs` files
after one `veryfront build`, and `git add -A` committed them.

Mark the cache root from `buildProduction()` instead of from another entry
point's startup, so the CLI build, the MCP build tool, and a direct API call
are all covered. It goes there rather than in `setupBuildDirectories()` because
a dry run skips that step and still populates the cache root.

Also document `.cache/` in the project-structure guide. Until now the only
explanation a developer got for the directory appearing in their tree was the
comment inside the generated `.gitignore`; the guide now names both cache
subdirectories, states that the directory ignores itself, and documents
`VERYFRONT_CACHE_DIR` for moving it out of the project.

Verified against the published 0.1.1229 repro: a hand-built adopt-path project
(own .gitignore listing only node_modules/, dist/, .env) is left with a clean
`git status --porcelain -uall` after `veryfront build` and after
`veryfront build --dry-run`, where 0.1.1229 leaves ten untracked bundles.
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