Status: Duplicate
Solution moved to #1670450: drupal_get_js() stable sort / drupal_add_js automatic weight
Original description
There is a weight and sorting issue with drupal_add_js, if that is called multiple times for the same js. This happens easily with the ['#attached']['js'] thing.
Understanding the problem
This is our test pseudocode.
Obviously, we want $script0 to be included before $script1.
$element['a']['#attached']['js'][$script0] = array();
$element['a']['#attached']['js'][$script1] = array();
$element['b']['#attached']['js'][$script0] = array();
$element['b']['#attached']['js'][$script1] = array();
Now in drupal_add_js():
// Tweak the weight so that files of the same weight are included in the
// order of the calls to drupal_add_js().
$options['weight'] += count($javascript) / 1000;
[..]
$javascript[$options['data']] = $options;
Effect:
When the script is added for the second time, no new elements are added to the $javascript array. The original weight of the scripts is overridden. Now they both have the same weight.
Later in drupal_get_js():
uasort($items, 'drupal_sort_css_js');
The sort is not stable, as none of php sort algorithms is.
Thus, it can happen that $script1 is included before $script0. Ouch!
Solution
Solution A (preferable):
- implement a stable sort
- make sure css and js items are always moved to the end of the array, when they are included again.
- the micro-weight will now be pointless.
Solution B:
Implement a counter for the micro-weight, instead of just count($javascript).
Related issues
The same problem has been reported in
#1388546: Adding CSS or JS files twice changes weight and
#1458436: drupal_add_js/css() weight trickery fails if called for the same files multiple times (duplicate)
I have no idea if this applies to D8, so I just report for D7.
Comments
Comment #1
donquixote commentedPatch for the css/js stable sort.
Comment #3
donquixote commentedDuh. I just ran the tests on my local, and they already fail without the patch.
I am going to test that with a patch that does nothing.
Comment #4
nod_tag
Comment #5
donquixote commentedFound it:
The stable sort does not help if we do not also make sure css is added at the end of the array.
In this comment I will upload a new test that I expect to fail without my fix, that is going to follow. This is to prove that the current solution does not work.
Comment #6
donquixote commentedComment #7
donquixote commentedCool!
EDIT:
I'd like to have a review from a real person.
After that, we can do some work on cleanup and comments.
Comment #8
donquixote commentedAnd now for 8.x.
New test expected to fail, as in #5.
Comment #9
donquixote commentedAnd now the fix.
Comment #10
robloachDo we want to remove the
drupal_sort_css_js()function? Adopt this to CSS as well?Comment #11
donquixote commentedFor D8, sure, let's remove :)
For D7 backport, we better keep the drupal_sort_css_js() for compatibility.
"Adopt this to CSS" -> the patch applies to js and css equally.
Comment #12
donquixote commentedRemoving the old code, and adding some commentary.
I am not sure how much of the old commentary we need to keep. We should focus on those questions that people reading this code actually have.
Maybe we need more information on the sort criteria, especially the first one with $item['group'].
Comment #13
tim.plunkettThis is a dupe of #1388546: Adding CSS or JS files twice changes weight
Comment #13.0
tim.plunkettAdd related issues, mention the "move to end of array".
Comment #13.1
donquixote commentedMention duplicate in issue description