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

  1. Setting preprocess to FALSE
  2. Adding attributes like type="text/plain" and data-cookieconsent to 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

CommentFileSizeAuthor
#6 screenshot-2025-11-17 11_33_26.png1.66 KBgrevil

Issue fork cookies-3557113

Command icon 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

grevil created an issue. See original summary.

anybody’s picture

I guess we should combine the resolution with #3557091: Ensure COOKiES runs last for libraries to ensure we have no other side-effects?

anybody’s picture

I think for the asset_injector submodule (which is also affected!) we might be able to remove the preprocess = FALSE
https://git.drupalcode.org/project/cookies/-/blob/2.x/modules/cookies_as...

because we there already disable the "preprocess" option in asset injector, see

The COOKiES service this asset belongs to (check your existing services here). You may add a new service here, if this is a filter for a not yet existing service. Also you may need to add further information to the service description for this use-case. Note, that js preprocessing is NOT compatible with the COOKiES service!

The "Preprocess JS" setting is disabled and can't be enabled.

grevil’s picture

Interesting. 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.

grevil’s picture

Status: Active » Needs review
StatusFileSize
new1.66 KB

Fixed cookies_gtag:
screenshot

Please review!

anybody’s picture

Indeed we found out that gtag.ajax.js doesn't have to be excluded. Klaro also doesn't exclude it!

Nice fix!

anybody’s picture

Status: Needs review » Needs work

Tests 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.

grevil’s picture

Status: Needs work » Needs review

Should be fixed now. Let's wait for the tests to succeed.

grevil’s picture

Status: Needs review » Needs work

Still fail.

grevil’s picture

Status: Needs work » Needs review

Whoa, 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.

anybody’s picture

Tests FTW! :)

grevil’s picture

Status: Needs review » Reviewed & tested by the community

The 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.

  • grevil committed 45a9106e on 2.x
    feat: #3557113 Setting "preprocess" false in "cookies_mySubmodule_alter...
grevil’s picture

Status: Reviewed & tested by the community » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

grevil’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.