Problem/Motivation

Gutenberg stuck loading when using it on Drupal 9.2 and have JS aggregation enabled. The reason is a wrong order of jquery_ui JS files, which speaks for an underlying Drupal core issue.

The screenshot beneath shows the errors in non aggregation mode.


controlgroup-min.js?v=9.2.0:9 Uncaught TypeError: t.widget is not a function
    at controlgroup-min.js?v=9.2.0:9
    at controlgroup-min.js?v=9.2.0:9
    at controlgroup-min.js?v=9.2.0:9
mouse-min.js?v=9.2.0:9 Uncaught TypeError: e.widget is not a function
    at mouse-min.js?v=9.2.0:9
    at mouse-min.js?v=9.2.0:9
    at mouse-min.js?v=9.2.0:9
widget-min.js?v=9.2.0:9 Uncaught TypeError: i is not a constructor
    at Function.t.widget (widget-min.js?v=9.2.0:9)
    at draggable-min.js?v=9.2.0:9
    at draggable-min.js?v=9.2.0:9
    at draggable-min.js?v=9.2.0:9
widget-min.js?v=9.2.0:9 Uncaught TypeError: i is not a constructor
    at Function.t.widget (widget-min.js?v=9.2.0:9)
    at resizable-min.js?v=9.2.0:9
    at resizable-min.js?v=9.2.0:9
    at resizable-min.js?v=9.2.0:9

There is a "hacky" workaround for Gutenberg in [3219569#comment-14146442] and a workaround for Drupal core at [3219569#comment-14153148].

Please check the Drupal core issue at #3222107: Library order asset weights do not work properly when a large number of javascript files is loaded between two jQuery UI libraries for further progress.

Why does it happen after the Drupal 9.2 deprecation?
Because of the jquery.ui deprecation process the core libraries and dependencies have been slightly changed.

Is it a core problem?
Quite likely. The problem does not seem to appear with Drupal core and e.g. CKEditor. But the bug seem to have been introduced by the jquery.ui changes. Until now I only found another issue, that describes a similar problem (see below).

Why does it "only" happening with Gutenberg?
It's not related to Gutenberg. It happens when there are a lot of Javascript files going to be used (more than 100) on a page. Gutenberg is using a lot of individual Javascriipt files. Therefore we see it there.

Steps to reproduce

  1. Install Drupal 9.2
  2. Install Gutenberg 8.x-2.x
  3. Enable the Gutenberg Experience for the article content type at /admin/structure/types/manage/article
  4. Open the add node page at /node/add/article
  5. You should see the error. Disable JS aggregation check the file order.

The problem is, that controlgroup-min.js and other jquery.ui files depending on jquery.ui widget-min.js are invoked before the widget-min.js file.

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Comments

szeidler created an issue. See original summary.

szeidler’s picture

Issue summary: View changes
thorandre’s picture

We discussed this in the Gutenberg issue queue status meeting today.
@szeidler will follow up to consider how we should move this along.

Considered major as it breaks Gutenberg (not critical as there is no data loss or security risks).

The issue itself is probably a Drupal Core issue, but as we're not sure if it will be fixed there we're considering solving this in other ways. A long term solution to this issue could be to remove jQuery as a dependency for Gutenberg. Currently we only need that for Drupal dialogue (for example when opening a modal) - we could find another solution for that, as Drupal Core also is.

Claudio Fabio Mazzarago’s picture

Hi,
I have 2 version of the same website, the first one is in production mode, the second is for testing. I have this problem on the first one (same console error) but not on the second one, I can provide logs or anything else if this could be helpful in finding solutions. bye Claudio.

szeidler’s picture

Thanks. Yes, there seems to be a bit of randomness going on, but it has to do with the order of jquery.ui libraries. Basically under some circumstances some of the jquery.ui widget libraries are appearing on the page, before the jquery_ui.widget.js file gets loaded. I actually even experienced it one one single Drupal 9.1 site as well.

My workaround was the following.

/**
 * Implements hook_js_alter().
 */
function mymodule_js_alter(&$javascript, AttachedAssetsInterface $assets) {
  // For an unknown reason the scripts that depend on jquery.ui.widget are
  // loaded before its dependency. Therefore we modify the weight here to
  // ensure the widget-min.js is invoked earlier.
  if (isset($javascript['core/assets/vendor/jquery.ui/ui/widget-min.js'])) {
    $javascript['core/assets/vendor/jquery.ui/ui/widget-min.js']['weight'] = -12;
  }
}

I'm currently trying to demonstrate the bug isolated just with Drupal core, to have a proof, that it's a Core bug. But since jquery.ui is getting more and more deprecated and replaced, I'm pessimistic, that this will be fixed before. So we might need to test the workaround above and check if we should add it to the Gutenberg module for the time being.

jkamizato’s picture

Thanks @szeidler.

This workaround worked for me.

Claudio Fabio Mazzarago’s picture

thanks @szeidler,
i try to put your code in my "core/lib/Drupal/Core/Render/theme.api.php". I believe this is the exact location because it contains the "hook_js_alter" function but don't work for me.
can you help me please?
thanks!

szeidler’s picture

You will need to add it to a custom module and replacing "mymodule" with the custom module name. I'm going to provide a patch for Gutenberg, then you would need to apply the patch to the Gutenberg module and it should resolve the issue.

Claudio Fabio Mazzarago’s picture

I tried with a custom module but it still doesn't work for me (and it broke my site) :'( . I hope in your patch! :crossfinger
thanks!

szeidler’s picture

Here's the workaround as patch for Gutenberg filed against 8.x-2.x, for everyone who need it.

szeidler’s picture

And since it seem to appear with version 8.x-1.x as well, here a patch for the older Gutenberg releases.

szeidler’s picture

I need to recreate the patches. They are missing a use statement

szeidler’s picture

Issue summary: View changes
Status: Active » Needs review
StatusFileSize
new961 bytes
new1.12 KB

Here are the updated patches for 8.x-2.x and for 8.x-1.x.

Thanks for testing and your feedback, if they are fixing the issue.

lise.heika’s picture

#13 8.x-1.x patch worked for me with GB 8.x-1.12 on drupal 9.2.0

e.devhart.io’s picture

#13 I can verify that 3219569-13-8.x-2.x.patch is working on Drupal 9.20. Thank you szeidler.

codebymikey’s picture

Nice work on the patches @szeidler, and it's particularly interesting that this only affects Gutenberg and isn't more public.

It'd be nice to know which release in D9 it started breaking in so we can see if it's related to Gutenberg's library dependency declarations or that D9 version.

Also does changing the weight like this not have implications on existing D8 sites if the weighting is handled differently? I haven't had time to look into this properly.

doxigo’s picture

Path #13 works as expected as of now

szeidler’s picture

Nice work on the patches @szeidler, and it's particularly interesting that this only affects Gutenberg and isn't more public

I did quite a bit of investigation, but still don't get the full picture here.

Why does it happen after the Drupal 9.2 deprecation?
Because of the jquery.ui deprecation process the core libraries and dependencies have been slightly changed.

Is it a core problem?
Not 100% sure. The problem does not seem to appear with Drupal core and e.g. CKEditor. But it seem to have been introduced by the jquery.ui changes. Until now I only found another issue, that describes a similar problem (see below).

Why does it "only" happening with Gutenberg?
No idea yet. I first thought it's a missing or wrong library dependency in Gutenberg. I removed and added dependencies, trying to influence the order without any luck. I found somethinig in the cshs issue queue, that is describing a similar problem: https://www.drupal.org/project/cshs/issues/3219960

Also does changing the weight like this not have implications on existing D8 sites if the weighting is handled differently

This we would need to test properly before a workaround like this could land in the module. Before Drupal 9.2 every jquery.ui plugin was properly defined as an own Drupal core library and invoked via dependencies. That ensured the correct order. In Drupal 9.2 and the deprecation process those deprecated libraries are still there, but not used by Drupal core anymore, e.g. as a dependency for the core/drupal.dialog library. They are now hardcoded as JS files for each of the libraries that need them, using a weight to bring them in the correct order. Which works fine for CKEditor and raw core pages - but somehow gets wrong when using Gutenberg.
Since Drupal < 9.1 used proper library dependencies for jquery.ui changing the weight should not have an influence, since the dependencies are more prioritized for the ordering of assets. But we need to test this carefully.

Claudio Fabio Mazzarago’s picture

It works for me after cleaning cache :)
thanks @szeilder

bnjmnm’s picture

When the jQuery UI assets were switched for deprecation purposes, it included tests that confirmed load order was the same before/after the change (but perhaps there are use cases it didn't cover). There's one notable difference: prior to the change the asset loading weights were provided based on full integer values https://github.com/drupal/drupal/blob/8.9.16, ranging from -12 to -7

GROUP 1: [-7] dialog
GROUP 2: [-8] button
GROUP 3: [-9] checkboxradio, resizable, draggable
GROUP 4. [-10]  autocomplete, controlgroup, form-reset-mixin, labels,  mouse, menu, tabbable
GROUP 5. [-11] data, disable-selection, escape-selector, form, focusable, ie, jquery1-7, keycode, plugin, position, safe-active-element, safe-blur, scroll-parent, unique-id, widget
GROUP 6. [-12] version

After the deprecation related changes, the weights now use decimal values between -12 and -11. The loading order was intentionally preserved, and we checked it against a manual review of jQuery UI's code

Since it looks like the problem is specific to aggregation, some possible come to mind

  • The aggregated files are not fully rebuilt
  • The aggregator does not know how to deal with decimal values for weights
  • Something within the dependency tree also loads these files with different weights. Perhaps something like a theme override?

The current solution in #19 looks risky as changing the weight of widget to -12 instructs it to load earlier than version, which (as seen in the image above) is a dependency widget. Heres the current config in core.libraries.yml

    assets/vendor/jquery.ui/ui/widget-min.js: { weight: -11.8, minified: true }
    assets/vendor/jquery.ui/ui/version-min.js: { weight: -11.9, minified: true }

The fact that that works, and is not reporting an error that widget can't find version may help expose the root cause.

szeidler’s picture

Status: Needs review » Needs work

Thanks for your detailed input @bnjmnm! This is really valuable.

Since it looks like the problem is specific to aggregation, some possible come to mind

The problem is not specific to aggregation, but with aggregation it gets directly visible. Without aggregation you "only" see errors in the console. I haven't noticed if and where those errors would break functionality. But when aggregation is enabled it will be visible since browser will stop processing the JS, which includes much more JS a single non aggregated file.

Something within the dependency tree also loads these files with different weights. Perhaps something like a theme override?

Yes, I'm suspecting also something like this. Because Drupal core by default and with its tests clearly shows that it has the correct order. I was testing it on a plain Drupal 9.2 installation with Seven as the backend theme. In Seven I found a library extend. In addition has Gutenberg a load of dynamic library handling, but I don't see an explicit use of jquery.ui. Only implicitly via core/drupal.dialog.ajax and its dependencies.

libraries-extend:
  core/jquery.ui:
    - seven/seven.jquery.ui

Setting it to "Needs work" per feedback in #20.

thorandre’s picture

Issue tags: +v2.1
jmickela’s picture

StatusFileSize
new732 bytes

I've been digging into this today and have found that the problem only occurs if you use a block library. I set up a relatively empty D9.2 site and loaded a node edit page with no block libraries enabled and did not get the error. I enabled the Example Block module and got the error. After a lot of debugging I found that in the Drupal core AssetResolver.php file, there's code that modifies the weight of individual Javascript files getting included. From the looks of it, if there's a very large number of JS files that are to be included the adjustment to the weight can end up being enough for a file to get loaded before a requirement. I adjusted the value a bit and it fixed the problem.

This patch changes that value, but ultimately it will have to be applied to Drupal Core. Please test it out and see if this fixes the issue for others as well.

maxilein’s picture

Status: Needs work » Needs review

(I am also using Seven as admin theme.) I first reported this error here: https://www.drupal.org/project/cshs/issues/3219960

I don't know if this is helpful: my errors are reported after

Layout was forced before the page was fully loaded. If stylesheets are not yet loaded this may cause a flash of unstyled content.  modernizr.min.js:3:5914

then all the trouble starts:

Uncaught TypeError: t.widget is not a function

bnjmnm’s picture

I did a significant portion of the work on the deprecation changes that seem to be causing the issue reported here, so I may be able to spot the root cause pretty quickly if I can reproduce the problem on my local environment. Could someone provide steps to reproduce on a fresh Drupal install with Gutenberg enabled? We went to great lengths to make this change non-disruptive, so it's possible this is surfacing an bug in core. If that turns out to be the case, I'll see what I can do to get this fixed in core instead of expecting contrib to work around something that was overlooked (possibly by me 🙈)

jmickela’s picture

I gave steps to reproduce on a clean install in #23, along with a fix that shouldn't break anything else.

From what I can tell, this line is causing the issue:

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

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.

In the patch I posted in #23 I just changed the 1000 divisor to 3000, which triples the number of files you would need to be loading to see this bug, but shouldn't be such a big change that it would break anything, especially since there's no predictable way to know ahead of time what the final weight will be, so I can't imagine any code would break if that value were to change a little. That change fixed the problem for me.

jmickela’s picture

StatusFileSize
new714 bytes

Reformatted patch to remove the web directory.

maxilein’s picture

Jmickela, thank you very much for the thorough analysis!
Your patch solved it for me as well. (And I am not using Gutenberg.)

This should be in core.

codebymikey’s picture

Thanks for the detailed write-up @jmickela and feedback @bnjmnm, I've created an issue to track this in core: #3222107: Library order asset weights do not work properly when a large number of javascript files is loaded between two jQuery UI libraries.

In terms of immediate fixes for affected sites, the solutions are to apply a patch against core which:

  1. Reverts the jQuery UI deprecation commit
  2. Switches to $options['weight'] += count($javascript) / 3000; or equivalent
szeidler’s picture

Issue summary: View changes
szeidler’s picture

Status: Needs review » Active

Thanks for all your input. I'm setting the issue status back to "Active", because the underlying problem will be tackled in the core issue #3222107: Library order asset weights do not work properly when a large number of javascript files is loaded between two jQuery UI libraries and there is nothing to review here anymore. We will keep the issue here open, since it will be important to have it visible for everyone using the module.

@thorandre @marcofernandes depending on the attention the core issue gets, we probably should link to the core issue from the project page as long as it is unresolved.

szeidler’s picture

PS: I'm credited everyone who provided input here and reviewed one of the patches, which will be granted when we close the issue. Thanks for your work.

thorandre’s picture

Let's discuss progress for this issue in the Gutenberg status meeting today at 15:00CEST. We need a proper solution for this without the need for a separate patch.

thorandre’s picture

Assigned: Unassigned » szeidler
davidtra’s picture

Same issue on Drupal 9.2.5 and Gutenberg Version: 8.x-2.0. The Gutenberg editor is stuck on the loading dialog forever. This issue only appeared recently, after some Drupal update in July.

As soon as I deactivate "Aggregate JavaScript files" in the Drupal performance settings it starts loading again.

The console logs following errors:

controlgroup-min.js?v=9.2.5:9 Uncaught TypeError: t.widget is not a function
mouse-min.js?v=9.2.5:9 Uncaught TypeError: e.widget is not a function
widget-min.js?v=9.2.5:9 Uncaught TypeError: i is not a constructor
widget-min.js?v=9.2.5:9 Uncaught TypeError: i is not a constructor
marcofernandes’s picture

@szeidler I'm thinking committing patch #13 so people don't have to patch the core every time they install Gutenberg or waste time figuring out the issue. If it gets fixed on core then we'll revisit this and remove the patch. Any objections?

  • marcofernandes committed 6721a47 on 8.x-2.x
    Issue #3219569 by szeidler, jmickela, Claudio Fabio Mazzarago, thorandre...

  • marcofernandes committed ffe0bfd on 8.x-1.x
    Issue #3219569 by szeidler, jmickela, Claudio Fabio Mazzarago, thorandre...
renguer0’s picture

Same problem here, tried without advagg and clearing all caches but Gutenberg stucks on Loading...

BTW no errors registered in our database, that's kinda weird. That's supposed to be solved?

marcofernandes’s picture

@renguer0 Could you please provide more information about your installation, what Drupal version and Drupal Gutenberg version?
This specific issue won't throw any errors to Drupal log since it's a client side (javascript) issue.

renguer0’s picture

@marcofernandes of course, I'm using 9.2.7 and tested stable and dev on Gutemberg. I don't see anything logged neither browser console.

szeidler’s picture

Same problem here, tried without advagg and clearing all caches but Gutenberg stucks on Loading...

You say "without advagg". Do you have Drupal core aggregated enabled or disabled? If enabled, could you try to disable and see if it changes anything?

renguer0’s picture

@szeidler oh I see, I lost myself when I read translated to spanish 'Keep files merged' (not agregated).

I tried it but it stills don't workinig disabling core agregattion. By the way, when I disable core agregattion and use CDN, I see that message:

Failed to load resource: the server responded with a status of 503 ()

Maybe it could helps. Tried to disable CDN but error persist, the page just freeze and there is no browser errors.

I'm clearing all caches when disabling agregattion or CDN.

szeidler’s picture

Are you working with a completely clean Gutenberg installation or with configured Gutenberg templates or are you trying to use Gutenberg with old existing CKEditor body content?

Failed to load resource: the server responded with a status of 503 ()

Which resource throws the error? We might want to create a separate issue for it, since it might be a different problem, than what has been addressed here.

benellefimostfa’s picture

Had the same problem for an existing project with "Allowed Formats" module enabled.
I've fixed by enabling gutenberg in the text format that the body uses, then enabling that text format it in the field settings.
Not sure if it makes sense, but it worked for me.

renguer0’s picture

@benellefimostfa thanks, it's working disabling Allowed formats module but without core agregattion.

That's supposed to work?

contiveros’s picture

StatusFileSize
new301.47 KB

I'm having some issues as well. I had it working in 9.1.2, and haven't tried to update to 9.2.X until I saw an all clear from the module. Still in the forever load loop.

Drupal 9.2.7
Gutenberg 8.X - 2.0
Example and cloud is disabled.

I had Gutenberg Bootstrap running and a custom Gutenberg module, but they were disabled to see if they could be the issue.

Added a screenshot of the console from Chrome.

Tried to disable the JS files in Development > Performance > Manage Javascript Files, but that keeps me in a loop trying to install Core, bur Core is like, "Hey, you already have a site here."

szeidler’s picture

Hi @contiveros,

I'm wondering if it is related to the Coro issue reported in #2990907: JsOptimizer preg_replace gives null as return.

Tried to disable the JS files in Development > Performance > Manage Javascript Files, but that keeps me in a loop trying to install Core, bur Core is like, "Hey, you already have a site here."

If you're not able to disable JS aggregation, this is makes it of course harder to to debug, but seems to be a different issue as well.

thorandre’s picture

Status: Active » Fixed

Status: Fixed » Closed (fixed)

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