Problem/Motivation

Following the #3113400: Deprecate more jQuery UI library definitions update, this was discovered as the order of jQuery UI assets could change depending on whether there is a sufficiently large library loaded between two jQuery UI dependent libraries, which exposed an underlying problem with how asset weights are interpreted.

The bug is a side-effect of using non-integer weights for assets in jQuery UI libraries.

In particular, this AssetResolver::getJsAssets() logic:

$options['weight'] += count($javascript) / 1000;

Based on @jmickela's findings:

The javascript array is an array of files currently staged to be included, and grows by one with every iteration though the array of libraries. If all the weights were integers this wouldn't have an impact on the loading order, but the weights in the jQuery UI library use decimals now.

If two files are processed far enough apart from each other in the array, but have weights very close to each other, this change is enough to change the order they get loaded.

Widget's weight starts at -11.8, and Controlgroup at -11.7, if there's exactly 100 files in the array between them then they'll end up with the same weight, if there's 101 files then Controlgroup will get loaded before widget. I just checked an on the page I was testing on, I'm getting around 200 individual files.

Note that while this issue was discovered with JS assets, it also occurs with CSS assets, and the test coverage in this issue demonstrates that.

Steps to reproduce

Use a render array similar to:

[
  '#attached' => [
    'library' => [
      'core/drupal.dialog',
      // This library contains at least 100 javascript entries.
      'jqueryui_library_assets_test/many-dependencies',
      'core/drupal.autocomplete',
    ],
  ],
];

Proposed resolution

TBD.

would the recommended resolution be to change the fractional part of the weights from tenths to thousandths so that it's much less likely to run into the bug?

The alternative is to try and revisit the AssetResolver logic and see if it can be made more deterministic without introducing its own subtle bugs e.g. changing the divisor from 1000 to 3000 or higher.

Remaining tasks

Provide an issue fork/patch.

User interface changes

None

API changes

TBD

Release notes snippet

TBD

Workaround:

Disable JavaScript aggregation at /admin/config/development/performance

CommentFileSizeAuthor
#80 3222107-80.patch1.31 KBSpokje
#79 3222107-79.patch840 bytesSpokje
#72 3222107_95x.patch24.02 KBbnjmnm
#72 test-only-js-95x.patch24.09 KBbnjmnm
#72 test-only-css-95x.patch24.15 KBbnjmnm
#60 interdiff_54-60.txt7.47 KBbnjmnm
#60 3222107-10x-60.patch17.89 KBbnjmnm
#54 3222107-54-10x.patch17.56 KBbnjmnm
#54 3222107-test-only-css.patch18.87 KBbnjmnm
#54 3222107-test-only-js.patch18.8 KBbnjmnm
#31 3222107-2.patch11.79 KBShubham Chandra
#22 twidget.png205.56 KBtrickfun
#11 3222107-jquery_ui_weight_fix-11.diff14.77 KBcodebymikey
#8 3222107-8.patch715 bytesjmickela
#6 3222107-6.patch714 bytescodebymikey
#4 interdiff_2-4.txt1.15 KBcodebymikey
#4 3222107-jquery_ui-order-4-TEST-ONLY-FAIL.patch13.6 KBcodebymikey
#2 3222107-jquery_ui-order-2-TEST-ONLY-FAIL.patch13.6 KBcodebymikey

Issue fork drupal-3222107

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:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

codebymikey created an issue. See original summary.

nod_’s picture

Component: javascript » asset library system
Status: Active » Needs review
Issue tags: +JavaScript

Nice find

codebymikey’s picture

Issue summary: View changes
codebymikey’s picture

Uploading a proposed fix by @jmickela in here to see if it passes the default Drupal tests.

The last submitted patch, 4: 3222107-jquery_ui-order-4-TEST-ONLY-FAIL.patch, failed testing. View results

jmickela’s picture

After thinking about it a bit, if non-integer weights are allowed I then I feel like changing the divisor to 3000 really isn't enough, this patch changes it to 30,000 instead. With this you'll need to load 3,000 JS files before the chance of a loading order issue comes up; assuming the weights used are tenths. If it's valid to use weights like -10.00001 then this approach is fundamentally flawed.

I think the real fix is to only allow integer weights and possibly increasing the divisor value as well. As it is, even with integer weights you can run into this problem if you're loading over 1,000 JS files. If it would work just as well to use something like 30,000 as the divisor, then I don't think there's a reason not to, that would make it very unlikely to run into this issue as I would imagine a site using 30,000 JS files would probably run into other issues.

nod_’s picture

can we get a patch with both the tests and the code change? because there is no guarantee this is fixed by the code :)

The "real" fix is #1945262: Replace custom weights with dependencies in library declarations; introduce "before" and "after" for conditional ordering where weights are not even a thing anymore.

In the meantime I think this is a good enough fix.

codebymikey’s picture

Attached a patch with @jmickela's fix along with the test.

bnjmnm’s picture

Status: Needs review » Needs work

Mentioned in the MR, but I think this is pretty close to RTBC, but I'd like the test coverage for this to not be dependent on jQuery UI since that has an expiration date likely happening before this fix is no longer needed. To be safe, there should probably be a new test-only patch with the refactored tests, while the MR can be the tests+fix.

Feel free to ping me on Drupal Slack when the test is refactored and I'll re-review, I'll be happy to see this one land.

larowlan’s picture

When we get to D10, and drop IE support, can we solve this with ES module imports and let the browser sort it out 😈?

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

dtarc’s picture

Patch in #11 worked for us.

maxilein’s picture

I'd divide by 7000 instead of 3000.

SocialNicheGuru’s picture

Patch in #11 worked for me too

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

trickfun’s picture

Patch doesn't works for me if bigpipe is enable.
drupal 9.3.14

maxilein’s picture

I have bigpipe enabled and it works just fine.
Why do you think it is connected with bigpipe?

trickfun’s picture

FileSize
205.56 KB

I have errors only when bigpipe is enabled.
The error occurred on all pages.

Alina Basarabeanu’s picture

Patch #11 works on drupal/core (9.4.2)

SamLerner’s picture

I can confirm that the .diff in #11 is working for me on Drupal 9.4.3

Wim Leers’s picture

Nowrie’s picture

Patch #11 also works on drupal/core (9.4.6)!

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

steveoriol’s picture

Patch #11 works also well on D9.4.8
The patch applies well, but after some tests, some js and css files are not loaded anymore (found) and blocks some pages of the website.

SamLerner’s picture

It sounds like the patch is consistently working. However, the merge request needs rebasing before it can be merged: https://git.drupalcode.org/project/drupal/-/merge_requests/954#note_34300

If we could get that done, I feel like this would be RTBC.

steveoriol’s picture

bad news for me, in fact even if the patch applies well to the core of Drupal 9.4.8,
I have some js and css files that are no longer loaded (found) and that block pages of the site.
And by removing the patch it works again...
[...]
I need the patch to use it with the new ckeditor 5 module for D9.
I tested the patch in version #8
For the moment it seems to work without any inconvenience.

Shubham Chandra’s picture

Re-rolled patch #11 in drupal 10.1.x

quotientix’s picture

#8 is working fine. Thanks for the patch!

chandu7929 made their first commit to this issue’s fork.

vipin.mittal18 made their first commit to this issue’s fork.

jrockowitz’s picture

The latest dev release of the Webform module is running into this issue via translations.

@see #3329097: Issues with CKEditor 5, tokens, translations

The patch works as expected but I'm not seeing any immediate workarounds

super_romeo’s picture

Merge request !954 on D9.5.1 works.

Chi’s picture

Priority: Normal » Major

Attaching media is completely broken in Umami profile when JS aggregation is enabled.
I think this can be considered as major issue.

redseujac’s picture

jrockowitz wrote in #36:

The latest dev release of the Webform module is running into this issue via translations.

The issue with CKEditor vs CSS/JS aggregation is NOT fixed in the most recent 6.2.x-dev version.

Notice this issue has nothing to do with translations, but with incompatibility of CKeditor and CSS/JS aggregation. If aggregation is disabled, you can write text in the textboxes with CKeditor, otherwise you cannot, because there are JS errors blocking CKEditor from working as expected.

For the errors see #20 @: #3329097: Issues with CKEditor 5, tokens, translations

This seems a major issue.

maxilein’s picture

It is a major issue. But the symtoms can differ from site to site depending on which css or js files you load... also in which order they are loaded.
Having said that: they can cause ALL kinds off issues!
The difficulty of diagnising this as the problem for any random js or css issue makes it a major issue in my opinion.
Since it is hard to get from a strange error to this issue ...

As a workaround until this is fixed: I am using #11 but I am dividing by 7000. Rarely had an issue.

bnjmnm’s picture

The offer in #12 (and the MR comment above it) still stands. Move the tests to not depend on jQuery UI assets, and it's ready for RTBC. Making that requested change will also address the test that is failing on the more recent patches/MRs. That's one of the scenarios I wanted to prevent with that request.

Here's what I said further up and it still stands:

I'm concerned about the tests for this fix being integrated into jQuery UI tests. aIt's very possible jQuery UI will be removed before the fixes in this issue are replaced by https://www.drupal.org/project/drupal/issues/1945262. Since this fix benefits users well beyond those using, jQuery UI, I'd like to be sure the tests aren't accidentally removed with jQuery UI. (even if it means adding tests that are VERY similar to the jQuery UI ones)

Mentioned in the MR, but I think this is pretty close to RTBC, but I'd like the test coverage for this to not be dependent on jQuery UI since that has an expiration date likely happening before this fix is no longer needed. To be safe, there should probably be a new test-only patch with the refactored tests, while the MR can be the tests+fix.

Feel free to ping me on Drupal Slack when the test is refactored and I'll re-review, I'll be happy to see this one land.

Just refactor that test and I think this is good to go.

maxilein’s picture

I agree. to #41
This is not jQuery specific.

Anybody’s picture

Just ran into this with layout_paragraphs on Drupal 9.5.3. Shouldn't we mark this "Critical"?

Anybody’s picture

Issue summary: View changes

Added

<h3>Workaround:</h3>
Disable JavaScript aggregation at <code>/admin/config/development/performance

to the issue summary.

gwenweb’s picture

#31 worked fine for me. Thanks !

Found this issue after having seen this kind of errors in the backoffice page console :

t / i / e .widget is not a function
i is not a constructor
Cannot set properties of undefined (setting 'formResetMixin") / (reading 'mouse')
$element.dialog is not a function

with a website using advagg, entity_browser and field_group

maxilein’s picture

Maybe we should rename this issue in order to make it more easily findable for people.
e.g.
"Large number of javascript files may cause multiple random script errors due to loading order of js files"

benJBmC’s picture

The patch #31 works for me too, thanks! I had an error using the ebt_slick_slider module when adding media to the custom block: Uncaught TypeError: $element.dialog is not a function

Anybody’s picture

We're running into this issue on several projects again and again in the last weeks with different results / error messages. I'm wondering why this didn't pop up earlier? Have there been related changes in recent core releases?

At the current state, I think it's important to find a solution here, should we perhaps increase the priority to critical?

In #10 @larowlan wrote

When we get to D10, and drop IE support, can we solve this with ES module imports and let the browser sort it out 😈?

Is that possible? Then we could at least look forward to a solution in 10.1.x (and should target that?!)

agoradesign’s picture

patch #31 works for us as well - had problems on taxonomy term edit pages after switching to ckeditor5

czigor’s picture

Priority: Major » Critical
Issue tags: -JavaScript +JavaScript

On my node form I have a CKeditor textarea field, a plain file field and a media field with media library widget.

Due to the broken js the files uploaded to the plain file field are not set to permanent which causes them to be deleted after 6 hours.

FiNeX’s picture

Hi, patch #31 works on my case: before the patch non admin users were not able to open the media library widget and other dialogs (when ckeditor5 was enabled). Thank you.

catch’s picture

Both the patch in #31 and the MR are failing tests. The next step here would be to try to fix that test failure. Agreed this should be critical.

catch’s picture

The MR needs to be re-done against 10.1.x and we need to use something other than jQuery UI to test it.

bnjmnm’s picture

Title: jQuery UI library order is incorrect when a large number of javascript files is loaded between two jQuery UI libraries » Library order asset weights do not work properly when a large number of javascript files is loaded between two jQuery UI libraries
Status: Needs work » Needs review
FileSize
18.8 KB
18.87 KB
17.56 KB

Created tests that aren't dependent on jQuery UI. Those tests also exposed that the same problem exists with CSS, so a fix was provided for that as well.

The last submitted patch, 54: 3222107-test-only-js.patch, failed testing. View results

The last submitted patch, 54: 3222107-test-only-css.patch, failed testing. View results

bnjmnm’s picture

Issue summary: View changes

Updated IS to make it clear jQuery UI was where it was discovered, but the issue is not specific to it.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +Needs Review Queue Initiative

I need to give complete kudos for the tests.

#54 shows this covers the problem for js/css

So the actual change looks good to me and matches the proposed solution from the summary.

larowlan’s picture

Status: Reviewed & tested by the community » Needs work

It pains me to put this back to needs work on the tests only, because its a long-standing critical - but I think we can improve the test in a few ways, and at least one of those changes (asserting a count) feels blocking

  1. +++ b/core/tests/Drupal/FunctionalTests/Libraries/ManyAssetsLoadOrderTest.php
    @@ -0,0 +1,69 @@
    +  public function testLoadOrder() {
    

    If we're touching this, could we add a docblock here (if not can be fixed on commit)

  2. +++ b/core/tests/Drupal/FunctionalTests/Libraries/ManyAssetsLoadOrderTest.php
    @@ -0,0 +1,69 @@
    +      if (str_contains($src, 'weighted_')) {
    +        // The test file filenames have numbers that match their loading weight,
    +        // extract just that number so we can use that to check file loading
    +        // order.
    ...
    +      if (str_contains($src, 'weighted_')) {
    +        // The test file filenames have numbers that match their loading weight,
    +        // extract just that number so we can use that to check file loading
    +        // order.
    

    Library entries support attributes, would it be simpler to add a data-weight attribute in the definitions and then we can use findAll('css', 'script[data-weight]') and similar for links.

    So that would remove the need for:
    * the array_filter
    * the explode, str_contains, substr, strpos

    I think it would make the test easier to read/understand.

  3. +++ b/core/tests/Drupal/FunctionalTests/Libraries/ManyAssetsLoadOrderTest.php
    @@ -0,0 +1,69 @@
    +    $this->assertSame(array_filter($js_files_sorted), array_filter($js_files));
    ...
    +    $this->assertSame(array_filter($css_files_sorted), array_filter($css_files));
    

    Let's assert the count of files here, if both are empty, this will still pass (Same for the css).

    We can probably use ::assertGreaterThan(0, count($js_files))

    So its not a hard-coded number that is subject to fluctuation and therefore more expensive to maintain.

bnjmnm’s picture

Addresses all the points in #59, great suggestions.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Reviewing the interdiff and looks as all points have addressed from #59

Neat trick with the data-weight.

larowlan’s picture

Updated issue credits

  • larowlan committed 001d5ab5 on 10.1.x
    Issue #3222107 by codebymikey, bnjmnm, chandu7929, Shubham Chandra,...
larowlan’s picture

Title: Library order asset weights do not work properly when a large number of javascript files is loaded between two jQuery UI libraries » [needs backport] Library order asset weights do not work properly when a large number of javascript files is loaded between two jQuery UI libraries
Version: 10.1.x-dev » 10.0.x-dev
Issue tags: +Bug Smash Initiative

Committed to 10.1.x

Moving back to 10.0.x for backport once we have a green test-run.

larowlan’s picture

Version: 10.0.x-dev » 9.5.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)

Backported in 10.0.x, needs re-work for 9.5.x because of the .es6.js files 😭 - going to be a lot of them, all empty

  • larowlan committed 8a0be0e2 on 10.0.x
    Issue #3222107 by codebymikey, bnjmnm, chandu7929, Shubham Chandra,...
Wim Leers’s picture

+++ b/core/lib/Drupal/Core/Asset/AssetResolver.php
@@ -259,7 +259,7 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize, Language
-            $options['weight'] += count($javascript) / 1000;
+            $options['weight'] += count($javascript) / 30000;

So was the actual root cause for the problem the division by 1000? i.e. that there was not enough precision?

In any case: superb work, @bnjmnm! 👏 Plus, this helps make #1945262: Replace custom weights with dependencies in library declarations; introduce "before" and "after" for conditional ordering more feasible, by having better test coverage for our decades old weight-based system before we transition to something better! 🥳

Wiktor7’s picture

+++ b/core/lib/Drupal/Core/Asset/AssetResolver.php
@@ -259,7 +259,7 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize, Language
-            $options['weight'] += count($javascript) / 1000;
+            $options['weight'] += count($javascript) / 30000;

Hello, this works in my case.

catch’s picture

Status: Patch (to be ported) » Needs work

Moving to needs work so it's clearer the patch needs a re-roll, vs. just a delayed cherry-pick.

Wim Leers’s picture

Note that per #3357678: The block editor menu havent the "editor" (see #19 + #20 + #21) that this is causing CKEditor 5 to fail to load correctly in certain contexts too. This issue fixed it. It first shipped in a release in 10.0.9.

… but it's not yet fixed in 9.5.x. So this would appear to still be quite important to backport.

Caveat: I have not verified if this problem occurred in 9.5.

agoradesign’s picture

I have encountered this problem on any 9.5.x site I've enabled CKE5 without this patch so far - but only on editing a taxonomy term

bnjmnm’s picture

The last submitted patch, 72: test-only-css-95x.patch, failed testing. View results

The last submitted patch, 72: test-only-js-95x.patch, failed testing. View results

redseujac’s picture

Wim Leers commented in #70:

Note that per #3357678: The block editor menu havent the "editor" (see #19 + #20 + #21) that this is causing CKEditor 5 to fail to load correctly in certain contexts too. This issue fixed it. It first shipped in a release in 10.0.9.

I'm working with 10.0.9 and I'm glad to tell that my problems with Webforms/CKEditor5 are solved now. Before it was impossible to write/edit text in some textboxes managed by CKEditor5 there.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Reroll for 9.5 looks good.

  • catch committed 8914d3ea on 9.5.x
    Issue #3222107 by codebymikey, bnjmnm, chandu7929, vipin.mittal18,...
catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed the backport to 9.5.x, thanks!

Spokje’s picture

Status: Fixed » Needs work
FileSize
840 bytes

Backport breaks HEAD of 9.5.x on PHP 7.3 (https://dispatcher.drupalci.org/job/drupal8_core_regression_tests/82519/...)

_If_ we decide to not rollback and do a 'hotfix', let's see if attached patch works.

Spokje’s picture

Right..., measure twice, code once.
There are _two_ arrow syntax functions in the test.

Let's try this again...

Spokje’s picture

Status: Needs work » Needs review

  • catch committed dfd1b1a2 on 9.5.x
    Issue #3222107 by codebymikey, bnjmnm, chandu7929, Spokje, vipin....
catch’s picture

Status: Needs review » Fixed

Whoops. Committed/pushed to 9.5.x, thanks!

MaxMendez’s picture

I'm using 9.5.9 and the problems seems to be solved for the admin user (user 1), but the problems seems to persist on user with low level of permissions.

MaxMendez’s picture

Sorry, my mistake, it is fixed but has been released core versión with this patch.

jonurace’s picture

#67 works for me- Thanks!!!

mr.pomelov’s picture

#72 work for me (Drupal 9.5.9, MySQL 5.7.30, PHP 8.1.7)

Anybody’s picture

Confirming this works fine! Very much looking forward to the next 9.5 patch release with this fix!

Wim Leers’s picture

Title: [needs backport] Library order asset weights do not work properly when a large number of javascript files is loaded between two jQuery UI libraries » Library order asset weights do not work properly when a large number of javascript files is loaded between two jQuery UI libraries

Yay!

Updating title.

Status: Fixed » Closed (fixed)

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

maxilein’s picture

Version: 9.5.x-dev » 10.1.x-dev
Issue tags: -JavaScript +JavaScript

The issue is back with D10.1.
Since the other issue was postponed to D11.x, can we please make a patch for D10.1.

Martijn de Wit’s picture

larowlan’s picture

Version: 10.1.x-dev » 9.5.x-dev

It's all the way back to 9.5

maxilein’s picture

Thanks. You are right. Forgive me! Same symptoms ... I'll investigate...

maxilein’s picture

It seems that https://www.drupal.org/project/simple_popup_views was this issue.
It behaved very much randomly like problems caused by this issue. All kinds of javascript file errors, without any logical source that varied completely from the number of installed and uninstalled modules. So I post it here. It may help someone.

maxilein’s picture

It turned out that it was just a coincidence of multiple contrib modules which did forget to migrate core/jquery to contrib before the upgrade to 10.1 and some missing dependencies in this context. Sorry and thank you.

gwvoigt’s picture

Does it work with 9.5.10? None of the patches apply to 9.5.10

ivnish’s picture

Already committed to 9.5, see #77

gwvoigt’s picture

Thank you! I'm on 9.5.10 and still having issues when aggregation is on. In random instances the ckeditor don't load properly.

cecrs’s picture

@gwvoigt

Check out this issue: https://www.drupal.org/project/drupal/issues/3370930

We were also still seeing problems with missing ckeditor5 toolbars, and it was caused by aggregate files not getting written to disk due to mismatched hashes. There isn't a patch for < D10, but it's minimal changes and easy to generate a patch for if you aren't on D10 yet. Appears to have resolved our issues.

maxilein’s picture

Is it possible that this also affects css at a simliar functionality?
When I aggregate css files not all styles are used.