fix(plugin): resolve crash on invalidate() in plugin mode - #2378
Conversation
🦋 Changeset detectedLatest commit: 9cd68cc The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2378 +/- ##
==========================================
+ Coverage 96.14% 96.23% +0.09%
==========================================
Files 12 12
Lines 1660 1675 +15
==========================================
+ Hits 1596 1612 +16
+ Misses 64 63 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit c801900. Configure here.
When used as a plugin the host (webpack-cli, webpack-dev-server, etc.) owns `compiler.watch()`, so `invalidate()` threw because the middleware has no `watching` of its own. Invalidate the host's `watching` instead (each child compiler's one for a `MultiCompiler` on webpack < 5.109) and warn when the compiler is not watching at all. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The fix has three branches and the PR tested two: the host's own watching and the warning when nothing is watching. Added coverage for the rest. A MultiCompiler with its own watching now asserts each child is invalidated exactly once -- MultiWatching already propagates, so this fails if the fallback loop runs as well and invalidates them twice. The fallback itself is driven by clearing the MultiCompiler's watching, which is the shape webpack < 5.109 has, and asserts both children are reached. Also covers the warning for a MultiCompiler watching nothing, and that the callback still runs in plugin mode.
c801900 to
e2ed96e
Compare
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
Included review availability: Your plan provides up to 8 included reviews per hour; 5 remain after this review. WalkthroughThe Merge Risk: ⚪ Minimal · up to This localized fix prevents invalidate() from crashing in plugin mode while preserving standalone behavior; no actionable merge-blocking risk remains after normal checks and review. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. (1 skipped: 1 unsupported.) ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning Some tools did not complete. Review the errors below. 🔧 ESLint
ESLint install failed: dependency version conflict. Check your lock file or package.json. 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: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Team
Run ID: a3d7ed57-edc8-425f-a380-db818c106f92
📒 Files selected for processing (4)
.changeset/plugin-mode-invalidate.mdsrc/index.jstest/__snapshots__/pluginMode.test.js.snap.webpack5test/pluginMode.test.js
Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.
Reported by Cursor Bugbot. The no-op guard warned but left the callback queued: ready() had already pushed it onto context.callbacks, and with nothing to invalidate no build ever drains them, so invalidate(callback) never returned. close() completes its callback on the same path. The watchings to invalidate are now collected before anything runs, so the no-op case is known before ready() is called and can complete the callback directly. Ordering is otherwise unchanged -- ready() still runs before invalidate(), which the 16 standalone invalidate tests cover. The callback takes the build result rather than an error, so it gets no stats here instead of close()'s null.

When used as a plugin the host (webpack-cli, webpack-dev-server, etc.) owns
compiler.watch(), soinvalidate()threw because the middleware has nowatchingof its own. Invalidate the host'swatchinginstead (each child compiler's one for aMultiCompileron webpack < 5.109) and warn when the compiler is not watching at all.Summary
What kind of change does this PR introduce?
Did you add tests for your changes?
Does this PR introduce a breaking change?
If relevant, what needs to be documented once your changes are merged or what have you already documented?
Use of AI
Note
Low Risk
Targeted fix to public
invalidate()behavior in plugin mode with tests; standalone path unchanged when middleware ownswatching.Overview
Fixes a crash when
invalidate()is called while webpack-dev-middleware runs as a plugin (isPlugin = true), where the middleware no longer owns awatchinginstance.invalidate()now uses the middleware’s ownwatchingwhen present (standalone usage). In plugin mode it forwards invalidation to the host’scompiler.watching, or to each child compiler’swatchingonMultiCompilerwhen top-levelwatchingis missing (webpack < 5.109). If nothing is watching, it logs a warning instead of throwing—aligned with existing plugin-modeclose()behavior.Plugin-mode tests cover host-owned invalidation and the no-watch warning; a changeset records the patch.
Reviewed by Cursor Bugbot for commit c801900. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit