Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
Currently, the default aggregation JS output looks like this:
<script src="/sites/default/files/js/js_BKcMdIbOMdbTdLn9dkUq3KCJfIKKo2SvKoQ1AnB8D-g.js"></script>
<!--[if lte IE 9]>
<script src="/sites/default/files/js/js_VhqXmo4azheUjYC30rijnR_Dddo0WjWkF27k5gTL8S4.js"></script>
<![endif]-->
<script src="/sites/default/files/js/js_Cry_2ymPxsxXR0OfM2CVnTbE0pTKEfbYOqTRKtLi0V8.js"></script>
The IE9 specific classList library in the middle results in generating 3 files in total, so browsers have to load 2-3 different files. That's because it has the same weight as other libraries and ends up below/between them.
Proposed resolution
Change the weight to -25, so it is explicitly the first and before all other elements, the result is this:
<!--[if lte IE 9]>
<script src="/sites/default/files/js/js_VhqXmo4azheUjYC30rijnR_Dddo0WjWkF27k5gTL8S4.js"></script>
<![endif]-->
<script src="/sites/default/files/js/js_gp2hn88-lr0GHwFrbN4bRDVoLZa-QiAkYi478GYUreA.js"></script>
Now browsers by default only have to load 1-2 files, we also have to generate/track fewer files in the file system.
Remaining tasks
User interface changes
API changes
Data model changes
Comment | File | Size | Author |
---|---|---|---|
#28 | lower_weight_of-2905036-28.patch | 975 bytes | Berdir |
#27 | lower_weight_of-2905036-27.patch | 979 bytes | Berdir |
#23 | lower_weight_of-2905036-23.patch | 828 bytes | andypost |
#23 | 2905036-interdiff-16.txt | 1016 bytes | andypost |
#16 | lower_weight_of-2905036-16.patch | 875 bytes | Wim Leers |
Comments
Comment #2
BerdirHere's a patch, not sure if we can test this? Also not sure if we could change something about the aggregation to make this work by default? AFAIK we'll also stop supporting IE9 soon, so I suppose we can just remove that library then, or at least stop depending on it (for BC, if someone else uses it)
I was looking into this because I was optimizing aggregation on a site with multiple remote libraries, by default you get something like this:
aggregated-file
ie9-file
aggregated-file
remote-file
aggregated-file
remote-file
remote-file
aggregated-fle
..
In total, I had 10 JS script files. With this patch and explicitly setting the weight of all my external libraries to -100, I was able to change it to:
remote-file
remote-file
remote-file
ie9-file
aggregated-fle
And only 6 JS script files (including IE9), so I'm saving 4 requests. I'm wondering if *that* (setting very low weight for external files) is something we could do by default?
Comment #3
BerdirComment #4
BerdirComment #5
BerdirComment #6
BerdirAh found https://www.drupal.org/node/2897971, which says workarounds will be removed in 8.5.x but we already no longer really support it.
So we could possibly change this issue to just remove it?
Comment #7
Wim LeersThis beautifully illustrates the problem of doing this in such a simple way: sometimes, the loading order matters. Script A assumes script B has already loaded, which assumes script X has already loaded.
For remote scripts, this is less likely to be a problem (many don't have dependencies on other scripts), but not guaranteed to not be a problem. So your trick definitely works for your case, but not in all cases, which means we can't do it in Drupal core :(
As we've said before, weights are a bad/broken system. Which is why Drupal 8 made big steps towards removing it.
That brings me to dependencies. Drupal 8 removed weights in favor of dependencies. Using dependencies, we can reason about which script load orders are valid.
Today, Drupal 8 still generates weights internally. That's why you end up with remote files interspersed with aggregates. But if we'd use dependency information, we could reason based on dependencies, which would allow us to do exactly what you did manually by setting external libraries to weight -100: we could load external libraries first, and then have far fewer aggregates.
(I realize this is not exactly a great explanation, but I hope it made sense. I can revisit this and explain it better later if necessary. Currently short on time.)
Comment #8
Berdir> Drupal 8 removed weights in favor of dependencies.
Except it didn't, not really ;)
core.libraries.yml has lots of weights :)
I don't think dependencies just magically solve all those problems. We already have dependencies and that's exactly why we end up with an order like my example above.
Lets say you have 2 external scripts (E1, E2) and two local scripts (L1, L2), L1 depends on E1, L2 depends on E2. That results in 3 possible orders, all are *correct* according to the dependencies and work:
1. E1, E2, L1, L2
2. E1, L1, E2, L2
3. E2, L2, E1, L1
However, only the first option results in good aggregation but there is no way that we can know that based on the dependencies. That system doesn't care about that. To optimize for that, we need to add some assumptions/rules on top of the dependencies. Weights is currently what we have, but we could also build logic to e.g. load external JS first as long as dependencies allow it. Doesn't change that we need some logic to go from multiple correct solutions to the one that is best optimized.
Comment #9
BerdirThe main point of this issue is simply to optimize an already existing weight, I don't think that makes it worse. Anything else is a separate issue anyway, just wanted to add a bit of background and it's something worth discussing *somewhere*.
Comment #10
Wim LeersIt doesn't. It only has it for the "old school ones", the libraries that also had explicit low weights in Drupal 7. Plus the libraries that are new that those libraries with low weights in Drupal 7 are now depending on in Drupal 8.
backbone
classList
domready
drupal
drupalSettings
html5shiv
jquery
jquery.once
jquery.ui
modernizr
normalize
(those all have ~-20 weights)
Plus some weird cases:
drupal.autocomplete
drupal.tabledrag
drupal.vertical-tabs
#1945262: Replace custom weights with dependencies in library declarations; introduce "before" and "after" for conditional ordering was committed and removed all remaining weights. It was then reverted because it broke a few things. And then it was never worked on again :(
That's not true. We still convert dependencies to weights, and that's what I was getting at in #7. See
\Drupal\Core\Asset\AssetResolver::getJsAssets()
:We conserve insertion order, but don't need to.
And we only generate a weight for each individual asset in the first place because we still have few weights lingering around. If we didn't have those (the ones quoted), then we could remove this altogether.
You're absolutely right!
+1
Yes, this please! We shouldn't introduce more uses of weights.
Comment #11
Wim LeersThat's also true.
I hadn't noticed in #7 that
classList
already has a weight :(Comment #12
Wim LeersSo then this is all that remains: add a comment explaining why this weight of 25 was chosen.
Comment #13
droplet CreditAttribution: droplet commentedSlightly off-topic:
Accurately 'lte IE9' is wrong. classList.js also support other methods that IE10/IE11 doesn't. Back to the time when we release D8.0.0, FF and Safari and Android also doesn't support classList well I think (But yeah, we only used add/remove in active-link.js, most of the users will not run into the bug)
I was suggested somewhere to use a simple polyfill with className inside the active-link.js directly. If anyone interested, raise an issue again :)
Comment #14
BerdirThen maybe keep it for now and just update the weight?
Added a comment.
Comment #15
nod_works for me
Comment #16
Wim LeersJust fixing a language nit.
Comment #17
xjmI think we should be more explicit into the comment as to why we're picking -25 instead of -99 or -26 or -24. After all, the difference between -25 and -21 is not that big. I originally assumed this had something to do with the IE 30 asset thing, but from the comments that doesn't seem to be the case at all.
Comment #18
BerdirThere is no other reason than being the first/lowest weight, there is no other reason for -25 other than the currently lowest is -22 and -25 is just the number I picked that is lower and still gives us a gap in case we need to add something more inbetween.
=> This is IMHO already in the comment, don't know how else to describe it, suggestions?
Comment #20
BerdirSetting back to needs work to get feedback on that.
Comment #21
borisson_I think it is clear enough as-is and don't know how to better describe that. So I feel this is RTBC, but not changing status to wait for @xjm's feedback
Comment #22
andypost> the currently lowest is -22 and -25 is just the number I picked that is lower
I bet this is what @xjm asked to add to comment
Comment #23
andypostI filed alternative issue to get rid of the problem for core #2955842: Deprecate classList library
But this one still makes sense for contrib which still use classList to work with SVG that is not supported in IE11
Comment #27
BerdirSo classlist has been deprecated in the other issue.
I'm closing this as outdated, don't expect it to still land, with a final reroll for 8.8.
Comment #28
BerdirAnd now the final final reroll because a typo was fixed in the deprecation message ;)