Problem/Motivation
This is a follow-up issue to #3416508: Skip generating aggregates that won't be used for stale asset requests.
All submodules use hook_js_alter() to conditionally modify JavaScript files when "knock out" is enabled. These modifications include
- Setting
preprocesstoFALSE - Adding attributes like
type="text/plain"anddata-cookieconsentto prevent script execution until consent is given
The problem is that these conditional modifications in hook_js_alter() are not compatible with how JavaScript aggregation caching works in Drupal. Even though aggregation changed significantly in Drupal 10.1, the caching of hook_js_alter() did not change. This means:
- When JavaScript aggregation is enabled, Drupal creates aggregate files and caches them
- The cache key doesn't account for conditional modifications based on runtime state (like whether knock out is enabled)
- This can result in incorrect cached aggregates being served, where scripts that should be modified are served unmodified, or vice versa
- The same aggregate URL might be generated for different scenarios (with/without knock out), leading to cache collisions
This is the same pattern that core modules like locale and ckeditor5 solved by using placeholder libraries that are conditionally attached, ensuring unique aggregate URLs based on whether the library is present or not.
Proposed resolution
Refactor the cookies submodules to use a placeholder library, following the same approach used by core modules locale and ckeditor5:
This approach ensures that:
- When knock out is enabled, the placeholder library is attached → unique aggregate URL → correct cache key
- When knock out is disabled, the placeholder library is not attached → different aggregate URL → separate cache entry
- The presence/absence of the library is part of the cache key, so aggregation handles it correctly
User interface changes
API changes
Data model changes
| Comment | File | Size | Author |
|---|---|---|---|
| #6 | screenshot-2025-11-17 11_33_26.png | 1.66 KB | grevil |
Issue fork cookies-3557113
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
anybodyI guess we should combine the resolution with #3557091: Ensure COOKiES runs last for libraries to ensure we have no other side-effects?
Comment #3
anybodyAdding the similar Klaro issue: #3557114: Setting "preprocess" false in "klaro_js_alter" could lead to unintentional problems with file aggregation
Comment #4
anybodyI think for the asset_injector submodule (which is also affected!) we might be able to remove the
preprocess = FALSEhttps://git.drupalcode.org/project/cookies/-/blob/2.x/modules/cookies_as...
because we there already disable the "preprocess" option in asset injector, see
The "Preprocess JS" setting is disabled and can't be enabled.
Comment #5
grevil commentedInteresting. The two scripts causing us problems (init.js from posthog and gtag.ajax) are present in the body after consent denied. Furthermore, gtag.ajax is not even loaded on initial load.
Only when COOKiES is installed, that library appears on the main page. Otherwise, its not even loaded. I wonder why.
Comment #6
grevil commentedFixed cookies_gtag:

Please review!
Comment #8
anybodyIndeed we found out that
gtag.ajax.jsdoesn't have to be excluded. Klaro also doesn't exclude it!Nice fix!
Comment #9
anybodyTests need to be fixed. Can we also fix posthog? Otherwise let's merge this as soon as it's green and create a separate MR here for posthog.
Comment #10
grevil commentedShould be fixed now. Let's wait for the tests to succeed.
Comment #11
grevil commentedStill fail.
Comment #12
grevil commentedWhoa, good thing we have the tests. My previous changes caused gtag.js to always be knocked, no matter what.
I just auto formatted the code and moved the for... in... loops to ".forEach", seems like this caused some issues. Probably a "this" that now has a different context. Anyway, I reverted the eslint changes again and tested manually locally. Works again.
Comment #13
anybodyTests FTW! :)
Comment #14
grevil commentedThe last test failure is definitely unrelated.
I tried to reproduce the behavior in the tests. Probably a race condition, since we never wait in the simple "testCookiesBanner" test. I'll merge this as is. We can create a follow-up issue, if we want.
Comment #16
grevil commentedComment #18
grevil commentedHere is the follow-up issue: #3558230: Fix "testCookiesBanner" test not succeeding.