fix: invalidate the pack when the generator changes - #722
Merged
Conversation
🦋 Changeset detectedLatest commit: 8aa3bfa 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 |
`generate` rewrites a module's own build result, and the filesystem cache restores that result without rebuilding the module -- so changing `generate` or `generatorOptions` changed nothing. The pack kept answering with the previous generator's bytes and its name, and only deleting the cache directory recovered. Reproduced: a second run configured for `avif` emitted `image.webp` with the first run's bytes and never called the new generator. Nothing per-module keys on a plugin, so the generator's identity goes into `cache.version` instead. Identity is the implementation's source rather than `getMinimizerVersion`, since a generator already travels to a worker as source and a custom one reports no version. This reaches the cache only from a configured plugin -- `plugins` or `optimization.minimizer` -- because webpack builds the cache strategy while it applies those; the README says so. Three cases cover it, in a new file: the rename surviving a restore (with the module asserted `cached`, not `built`), changed bytes re-encoding, and a changed generator or changed options re-running. The first two pass without the fix; the last two fail.
alexander-akait
force-pushed
the
fix/generate-cache-version
branch
from
September 4, 2026 15:01
650bb5e to
dd939bd
Compare
alexander-akait
changed the base branch from
test/generate-option-coverage
to
main
September 4, 2026 15:01
`generate` takes an array, and the identity the pack's version carries reads one — but nothing drove that branch, so it sat at 0 hits while the single generator path had 4. Same two-run shape as the other cases: an array of one generator, then an array naming a different one, which has to re-encode.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #722 +/- ##
==========================================
+ Coverage 94.73% 94.88% +0.14%
==========================================
Files 4 4
Lines 1102 1114 +12
Branches 386 391 +5
==========================================
+ Hits 1044 1057 +13
+ Misses 51 50 -1
Partials 7 7 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
generaterewrites a module's own build result, and the filesystem cache restores that result without rebuilding the module — so changinggenerateorgeneratorOptionschanged nothing. Reproduced: a second run configured foravifemittedimage.webpwith the first run's bytes and never called the new generator. Silent, and only deleting the cache directory recovered.Nothing per-module keys on a plugin, so the generator's identity goes into
cache.version. Identity is the implementation's source rather thangetMinimizerVersion, since a generator already travels to a worker as source and a custom one reports no version. This reaches the cache only from a configured plugin —pluginsoroptimization.minimizer— because webpack builds the cache strategy while it applies those; the README says so.Based on #721 rather than
main: the README paragraph this extends is added there. Please merge that one first.What kind of change does this PR introduce?
fix
Did you add tests for your changes?
Yes —
test/generate-filesystem-cache.test.js, four cases across two compiler runs sharing a cache directory. The rename surviving a restore (with the module assertedcached, notbuilt) and changed bytes re-encoding both pass without the fix; a changed generator and changedgeneratorOptionsboth fail without it.Does this PR introduce a breaking change?
No. A pack written before this is invalidated once, since the version it was written under no longer matches.
If relevant, what needs to be documented once your changes are merged or what have you already documented?
Documented here, in the
generatesection: that the pack is invalidated by a changed generator, and that the plugin has to be in the config for it to be — a plugin applied by hand afterwebpack()returns is too late.Use of AI
Claude Code found and fixed this. It went looking after the tests in #721 closed the watch-mode gap, first ruling out the canonical defect by running three builds under
infrastructureLogging.debugand confirming zeroPack got invalid because of write to:lines with the probe shown to be capturing output. The bug then surfaced on the next hypothesis. Its first probe missed it — two generators built by the same factory had identical source and differed only by closure, which is also what settled on source as the identity — and the fix was confirmed by A/B on one probe with nothing else changed. Reading webpack's own ordering is what established thepluginsrequirement, after the first version of the test applied the plugin post-construction and failed.🤖 Generated with Claude Code
https://claude.ai/code/session_016TQeNpahUSDUjD2Crugy5H
Generated by Claude Code