fix(prerender): warn and keep first output when two routes collide - #4491
fix(prerender): warn and keep first output when two routes collide#4491sobol-sudo wants to merge 2 commits into
Conversation
|
@sobol-sudo is attempting to deploy a commit to the Nitro Team on Vercel. A member of the Team first needs to authorize it. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughChangesPrerender collision handling
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/prerender/prerender.ts`:
- Around line 114-117: Update the route deduplication map usage in the prerender
flow to key both lookups and insertions by the resolved filePath used for
writing, rather than the raw route.fileName. Ensure the checks and updates
around routeByOutputFile consistently use filePath so filename aliases resolving
to the same output are treated as one target.
In `@test/prerender/collision.test.ts`:
- Around line 20-40: Wrap the Nitro lifecycle operations in the collision test,
including prepare, copyPublicAssets, prerender, and build, in a try/finally
structure, and move nitro.close() into the finally block so it always executes
when setup or prerendering fails. Keep the existing warning capture and
operation order unchanged.
- Around line 42-52: Update the collision assertions in the prerender test to
require that the intended winning route is “/other”, rather than deriving the
expected content from written[0].route. Also verify the collision warning
explicitly names both competing routes, while preserving the existing
single-file assertion.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: bb3442a2-7c28-4070-9ee1-57bf1ecdc643
📒 Files selected for processing (3)
src/prerender/prerender.tstest/prerender/collision.test.tstest/prerender/fixture/server.ts
🔗 Linked issue
Resolves the dedup half of #4487. The other half, the non-atomic write, is #4488 — the two are independent and this branch is cut from
main, not from that one.❓ Type of change
📚 Description
Two prerender routes can resolve to a single output file —
/otherand/other/index.htmlboth becomeother/index.htmlunderautoSubfolderIndex. Nitro renders both and writes both to that one path, so the file that ships is whichever render happened to finish last, and nothing in the output says a route was discarded.Nuxt produces exactly this pair without the user asking: it adds a prerender route
/index.htmlalongside the page route/wheneverssr: false, and raisesprerender.concurrencyabove 1.The resolved
fileNameis only known after a route has been rendered, so this cannot be deduped when routes are queued. This tracks the file each route resolved to and, when a second route resolves to a file that is already taken, warns and skips the write instead of replacing the first route's output:The skipped route is marked
skip, so it already renders as(skipped)in the prerender log throughformatPrerenderRoute. The file is claimed synchronously before the write is awaited, so a concurrent render resolving to the same file sees it as taken.Which of the two routes wins is still the one that finished first, and with
concurrency > 1that is not deterministic. Making it deterministic would mean ordering the writes, which seemed like a bigger change than this warrants — the point here is that the build no longer silently discards a render, and the warning names both routes so the duplicate can be removed from the route list. Happy to go further if you would prefer the winner to be pinned to route order.📝 Checklist
test/prerender/collision.test.tsbuilds a small fixture with both routes and asserts the warning fires once, that only one route claims the file, and that the file holds that route's render. It fails onmain(no warning, both routes recorded as written) and passes with this change.Locally:
test/unit174 passed / 2 skipped,tsc --noEmitclean,oxlintandoxfmt --checkclean.