Visitar URL original
CSS/lazy/hmr: asset resource referenced in CSS isn't available to lazy loaded javascript chunk · Issue #20800 · webpack/webpack · GitHub
Skip to content

CSS/lazy/hmr: asset resource referenced in CSS isn't available to lazy loaded javascript chunk #20800

Closed

Description

@Knagis

Have you used AI?

None

Bug Description

When the same asset is included in both .css file (with experiments.css) and imported in an asynchronously loaded lazy chunk, it throws at runtime.

Link to Minimal Reproduction and step to reproduce

https://github.com/Knagis/webpack-css-lazy-font-issue

Expected Behavior

the asset resource is available in both CSS and JS chunks

Actual Behavior

ERROR
Cannot find module './font.woff2'
    at __webpack_require__ (http://localhost:8080/main.js:216:21)
    at fn (http://localhost:8080/main.js:415:21)
    at eval (webpack:///./mod.js?:2:69)
    at ./mod.js (http://localhost:8080/mod_js.js:18:1)
    at __webpack_require__ (http://localhost:8080/main.js:221:32)
    at fn (http://localhost:8080/main.js:415:21)

Environment

System:
    OS: Windows 11 10.0.26200
  Binaries:
    Node: 24.11.1
  Packages:
    html-webpack-plugin: ^5.6.6 => 5.6.6
    webpack: ^5.106.0 => 5.106.0
    webpack-cli: ^7.0.2 => 7.0.2
    webpack-dev-server: ^5.2.3 => 5.2.3

Is this a regression?

None

Last Working Version

No response

Additional Context

also fails on webpack 5.104.1, possible earlier as well.

Activity

  1. Knagis commented on Apr 9, 2026

    @Knagis
    ContributorAuthor

    this does work when using css-loader/mini-css-extract-plugin instead of experiments.css

  2. xiaoxiaojx commented on Apr 9, 2026

    @xiaoxiaojx
    Member

    Hi @Knagis , thanks a lot for identifying several bugs and suggesting improvements — we’ll fix them as soon as possible.

  3. self-assigned this
    on Apr 9, 2026
  4. added 2 commits that reference this issue on Apr 9, 2026
    7bd8e08
    846a6fb
  5. added a commit that references this issue on Apr 12, 2026
    5e7591b
  6. Knagis commented on Jun 1, 2026

    @Knagis
    ContributorAuthor

    @alexander-akait fyi - this issue isn't fully fixed.

    unfortunately i can't figure out the reproduction, it now happens within storybook where everything is lazily loaded, but the result is the same: JS code throws Cannot find module './font.woff2'. The basic structure is the same - the woff2 file is referenced both in .css file (imported as side effect via a .js file) and in different .js file, but what is the exact order of the imports and at build time i haven't been able to figure out.

  7. alexander-akait commented on Jun 2, 2026

    @alexander-akait
    Member

    @Knagis Very strange we have a lot of tests around it, maybe edge case, without reproducible test repo it very hard to say, is it only for HMR right?

  8. Knagis commented on Jun 4, 2026

    @Knagis
    ContributorAuthor

    still no luck with reproduction (didn't find time to fight with that), colleague found the issue also without storybook build..

    in the meantime this is the vibe coded patch they say solves the issue locally (i didn't test this - but perhaps it provides some hint to you)

    Root cause

    The Inter .woff2 is referenced from both CSS (fonts/Inter/inter.pcss) and JS
    (evo-roulette-new/src/common/assets/const.ts). On the lobby build the asset module is emitted
    CSS-only. On the next (game) build, webpack's incremental moduleMemCaches2 decides the asset
    module is "unchanged" — it only compares outgoing connections — so it reuses the cached module
    hash, skips NormalModule.updateHash, and never re-runs the _sourceTypes reset from upstream fix
    #20801. Result: no JS code factory is generated for
    the asset, and webpack_require throws at runtime. AssetGenerator.getTypes() derives its
    output from incoming origin types (CSS vs JS) — the one input the cache wasn't tracking.

    Fix

    Patch lib/Compilation.js (.yarn/patches/webpack.patch) so the affected-modules check also tracks
    each asset module's incoming origin-type signature. When a CSS-only asset becomes JS-referenced,
    its cache entry is invalidated, the hash recomputes, and the upstream _sourceTypes fix fires —
    producing the JS factory in the new chunk. Asset-gated, so JS/CSS modules pay only one string check.

    diff --git a/lib/Compilation.js b/lib/Compilation.js
    index 66a5f2857b8019ad8d5e019e9ef2879da45264b3..276a008893de13a1d0552eb9dcf49a860738fb8f 100644
    --- a/lib/Compilation.js
    +++ b/lib/Compilation.js
    @@ -2884,6 +2884,28 @@
     		 * @param {Module} module module
     		 * @returns {References} references
     		 */
    +		/**
    +		 * https://github.com/webpack/webpack/issues/20800 — for asset modules,
    +		 * the set of source types returned by AssetGenerator.getTypes() depends
    +		 * on the *types* of the incoming connection origin modules (CSS vs JS).
    +		 * Track that signature so memCache2 is invalidated when a previously
    +		 * CSS-only asset becomes JS-referenced (e.g. via a newly-activated
    +		 * lazy entry). Without this, the hash recomputation in
    +		 * NormalModule.updateHash never fires and the JS code factory for the
    +		 * asset is missing from the new chunk at runtime.
    +		 * @param {Module} module module
    +		 * @returns {Set<string> | undefined} origin source-type signature, or undefined for non-asset modules
    +		 */
    +		const computeAssetOriginTypes = (module) => {
    +			if (!module.type || !module.type.startsWith("asset/")) return undefined;
    +			const result = new Set();
    +			for (const connection of moduleGraph.getIncomingConnections(module)) {
    +				if (connection.originModule) {
    +					result.add(connection.originModule.type.split("/")[0]);
    +				}
    +			}
    +			return result;
    +		};
     		const computeReferences = (module) => {
     			const id = /** @type {ModuleId} */ (chunkGraph.getModuleId(module));
     			/** @type {Map<Module, ModuleId> | undefined} */
    @@ -2914,7 +2936,8 @@
     					queue.push.apply(queue, block.blocks);
     				}
     			}
    -			return { id, modules, blocks };
    +			const assetOriginTypes = computeAssetOriginTypes(module);
    +			return { id, modules, blocks, assetOriginTypes };
     		};
     		/**
     		 * Compares references.
    @@ -2925,7 +2948,7 @@
     		 * @param {(string | number | null)[]=} references.blocks blocks
     		 * @returns {boolean} ok?
     		 */
    -		const compareReferences = (module, { id, modules, blocks }) => {
    +		const compareReferences = (module, { id, modules, blocks, assetOriginTypes }) => {
     			if (id !== chunkGraph.getModuleId(module)) return false;
     			if (modules !== undefined) {
     				for (const [module, id] of modules) {
    @@ -2949,6 +2972,13 @@
     				}
     				if (i !== blocks.length) return false;
     			}
    +			if (assetOriginTypes !== undefined) {
    +				const current = computeAssetOriginTypes(module);
    +				if (current.size !== assetOriginTypes.size) return false;
    +				for (const t of current) {
    +					if (!assetOriginTypes.has(t)) return false;
    +				}
    +			}
     			return true;
     		};
  9. Knagis commented on Jun 4, 2026

    @Knagis
    ContributorAuthor

    @alexander-akait found the repro (well, AI again helped)

    cacheUnaffected: true
    

    with this enabled, the previous reproduction still shows the issue:
    https://github.com/Knagis/webpack-css-lazy-font-issue

  10. alexander-akait commented on Jun 4, 2026

    @alexander-akait
    Member

    @Knagis Can you try - #21100?

  11. Knagis commented on Jun 4, 2026

    @Knagis
    ContributorAuthor

    Thank you, i will do that, but won't be very fast, hopefully late today. i still need to fix my webpack patches to get from 106.2->107.2.

  12. alexander-akait commented on Jun 4, 2026

    @alexander-akait
    Member

    Feel free to write me, if it will be fix your problem I will merge

  13. Knagis commented on Jun 4, 2026

    @Knagis
    ContributorAuthor

    @alexander-akait I can confirm that the branch from #21100 does indeed fix the issues we were seeing. we have two known places that trigger it (one within storybook and another in our standalone build) and both are working fine with the fix.

  14. alexander-akait commented on Jun 5, 2026

    @alexander-akait
    Member

    Great, will be a part of the next release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Fields

Priority

None yet

Effort

None yet

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions