fix(unplugin): Avoid generating empty routes#2642
Conversation
✅ Deploy Preview for vue-router canceled.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR adds a test case for handling nested Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/router/src/unplugin/codegen/generateRouteRecords.ts (1)
22-28:⚠️ Potential issue | 🟠 MajorMissing
.filter(Boolean)for root-level children.The same empty-route scenario that's fixed at line 101 can occur here. If a root-level child node is non-matchable with no children (lines 33-35),
generateRouteRecordsreturns'', and the join would produce invalid JavaScript like[,\n{...}]or[{...},\n].Proposed fix to apply the same filter
if (node.isRoot()) { return `[ ${node .getChildrenSorted() .map(child => generateRouteRecords(child, options, importsMap, indent + 1)) + .filter(Boolean) .join(',\n')} ]` }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/router/src/unplugin/codegen/generateRouteRecords.ts` around lines 22 - 28, The root branch in generateRouteRecords (when node.isRoot()) maps over node.getChildrenSorted() but doesn't filter out empty return values from generateRouteRecords, so non-matchable children can produce '' and create invalid array output; update the root branch to first filter out falsy results (e.g., .filter(Boolean)) before mapping and joining (same approach used elsewhere in generateRouteRecords), keeping the rest of the call using generateRouteRecords(child, options, importsMap, indent + 1) so empty strings are excluded from the joined array.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@packages/router/src/unplugin/codegen/generateRouteRecords.ts`:
- Around line 22-28: The root branch in generateRouteRecords (when
node.isRoot()) maps over node.getChildrenSorted() but doesn't filter out empty
return values from generateRouteRecords, so non-matchable children can produce
'' and create invalid array output; update the root branch to first filter out
falsy results (e.g., .filter(Boolean)) before mapping and joining (same approach
used elsewhere in generateRouteRecords), keeping the rest of the call using
generateRouteRecords(child, options, importsMap, indent + 1) so empty strings
are excluded from the joined array.
There was a problem hiding this comment.
Pull request overview
Fixes route code generation in the router unplugin to avoid emitting “empty routes” when route nodes are deleted (e.g., via beforeWriteFiles) but empty intermediate folders remain in the route tree.
Changes:
- Filters out falsy generated child route-record strings during
childrenarray generation to prevent empty array slots.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
posva
left a comment
There was a problem hiding this comment.
Thanks for the PR!
This is probably not the right fix. Maybe the delete is leaving some unused nodes in the tree or not cleaning itself from the parent.
A unit test for the tree is also needed
commit: |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2642 +/- ##
==========================================
+ Coverage 85.58% 85.96% +0.37%
==========================================
Files 86 88 +2
Lines 9960 10087 +127
Branches 2285 2321 +36
==========================================
+ Hits 8524 8671 +147
+ Misses 1423 1405 -18
+ Partials 13 11 -2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/router/src/unplugin/codegen/generateRouteRecords.ts`:
- Around line 22-28: The current loop in generateRouteRecords.ts mutates
node.children during forEach (child.delete()) and won't remove parents that
become empty after their children are pruned; change to a safe post-order
pruning: traverse children first (recursively prune each child), collect
children to delete (using child.isMatchable() and child.children.size === 0
checks after recursive pruning), then delete them in a separate pass using
child.delete(); alternatively implement a separate cleanup pass (pruneNode) that
returns whether a node should be deleted so parent callers can remove now-empty
non-matchable nodes. Ensure references to node.children, child.isMatchable(),
and child.delete() are used in the new post-order logic.
|
I have revised the logic for skipping lone parent nodes and added unit test. |
|
I discovered an issue during subsequent testing, if the file structure is |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/router/src/unplugin/core/tree.ts`:
- Around line 212-216: The cascade delete can climb to the root and trigger the
"Cannot delete the root node" error; modify the condition around the recursive
delete (the block using this.parent.isMatchable(), this.parent.children.size and
calling this.parent.delete()) to guard against deleting the root—e.g. check that
this.parent is not the root (use whatever root predicate exists or ensure
this.parent.parent !== undefined) before calling this.parent.delete(); update
the condition so the root node is never passed to delete().
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ble node is deleted
|
Just a moment. I've found some other issues. I'll fix them. |
|
Hi @posva ,I find a new problem. router
When I try to delete route start with a capital letter in beforeWriteFiles, an error is reported. |
…hable node is deleted
|
I have already dealt with all the issues. |
|
Hi @posva I have already dealt with all the issues. Could you spare some time to review this PR. |





fix #2641
Summary by CodeRabbit
Release Notes
Tests
Bug Fixes