-
Notifications
You must be signed in to change notification settings - Fork 5k
Don't emit a CSS chunk for files whose import resolution failed in the dev server #31945
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5247,9 +5247,19 @@ | |
| // Find CSS entry points. Originally, this was computed up front, but | ||
| // failed files do not remember their loader, and plugins can | ||
| // asynchronously decide a file is CSS. | ||
| // | ||
| // A file whose import-record resolution failed also has a `Some` | ||
| // css row: `run_resolution_for_parse_task` parks the parsed | ||
| // stylesheet there so teardown can drop it. Such files have no | ||
| // parts (the invariant the loop above filters by), and must not | ||
| // become CSS chunks — the loop above already removed them from | ||
| // `css_entry_points`. | ||
| let css = asts.items_css(); | ||
| let parts = asts.items_parts(); | ||
| for entry_point in &self.graph.entry_points { | ||
| if css[entry_point.get() as usize].is_some() { | ||
| if css[entry_point.get() as usize].is_some() | ||
| && parts[entry_point.get() as usize].len() != 0 | ||
| { | ||
|
Check failure on line 5262 in src/bundler/bundle_v2.rs
|
||
|
Comment on lines
+5260
to
+5262
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟣 Pre-existing, but adjacent to this fix: there's a second removal path the recovery loop still undoes. When Extended reasoning...What the gap is. The recovery loop at L5259-5269 re-inserts into Concrete walkthrough. Take a CSS file Why the new gate doesn't catch it. The PR's gate keys on the same invariant the loop above uses to enter the failure branch — non-empty parts. A file that fails via Impact. Milder than the bug this PR fixes: because the file parsed successfully, Pre-existing. Before this PR the loop checked only Possible fix (if you want to cover it here). Either also clear |
||
| start.css_entry_points.put( | ||
| Index::init(entry_point.get()), | ||
| CssEntryPointMeta { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴 This comment is now stale: PR #31905 (90589f9, merged into this branch via 2fd8e0d) changed
run_resolution_for_parse_taskto drop the parsed stylesheet rather than park it on the graph row — see L5744-5756, whose comment explicitly says "It must not be parked on the graph row either... the graph row for this file staysNone". After that merge,css[ep]isNonefor the resolution-failed case, so the existing.is_some()check already excludes it and the newparts.len() != 0guard is dead for its documented purpose. Either drop this change as superseded by #31905, or keep the guard as defense-in-depth but rewrite the comment so it stops describing behavior that no longer exists.Extended reasoning...
What the bug is
This PR and PR #31905 both fixed the same dev-server crash (a CSS file whose
url()/@importresolution fails was being emitted as a CSS chunk), but they fixed it in different places. #31905 landed onmainfirst and was then merged into this branch via 2fd8e0d. The merge produced no textual conflict, so both fixes now coexist — but the new comment at L5251-5256 describes the pre-#31905 behavior ofrun_resolution_for_parse_task, which #31905 explicitly removed.The contradiction
Somecss row:run_resolution_for_parse_taskparks the parsed stylesheet there so teardown can drop it."result.ast.css.take()+drop_in_placeand says: "It must not be parked on the graph row either... the graph row for this file staysNone."These two comments, ~500 lines apart in the same file, describe mutually exclusive behavior of the same function. The L5251 comment is the one that's wrong on current HEAD.
Step-by-step proof
git merge-base --is-ancestor 90589f93 HEAD→ yes;git merge-base --is-ancestor 90589f93 953e052→ no. So bundler: fix dev server crash when a CSS rebuild fails import resolution #31905 was not in this PR's base when the comment was written (it was accurate then), but is in this branch now after the merge.run_resolution_for_parse_taskhits the resolution-failure path → L5752 takesresult.ast.cssand drops it → the graph'scss[source_index]staysNone.finish_from_bake_dev_serverat L5260:css[ep].is_some()isfalsefor that file, so the entry is skipped beforeparts[ep].len() != 0is ever evaluated.Why existing code doesn't prevent it
This is a semantic merge conflict — git saw no overlapping hunks, so the merge at 2fd8e0d applied cleanly. Nothing in the build or tests flags two contradictory comments, and the redundant guard is behaviorally harmless, so CI stays green.
Impact
No runtime bug — the behavior is correct either way (#31905 already prevents the crash). The problems are:
How to fix
Pick one:
parts.len() != 0guard as belt-and-suspenders, but rewrite the comment to stop claimingrun_resolution_for_parse_taskparks the stylesheet — e.g. note that it's a defensive check mirroring the empty-parts filter in the loop above, in case any other path leaves aSomecss row with no parts.