This is one of those "oh... PHP" issues that is so bizarre it's *almost* funny, except it causes lost hours of work trying to figure out what's happening.

The end result is that the "version" string (or the first character of it) replaces the first character of the JS path. So if your library is version "1.0" and your JS path is "sites/all/modules/mymodule/library.js", the path gets clobbered and turns into "1ites/all/modules/mymodule/library.js". Obviously this causes the JS file to not actually get added to the page, as the path is wrong.

This problem only manifests itself when using the "shorthand" library syntax.

To reproduce. Add a library hook such as this to a custom module:

function mymodule_library() {
  $libraries['mylibrary'] = array(
    'title' => 'My Module: My Library',
    'version' => '1.0',
    'js' => array(
      drupal_get_path('module', 'mymodule') . '/mylibrary.js',
    ),
  );

  return $libraries;
}

Then (for simplicity's sake), in hook_init() add your library to the page:

function mymodule_init() {
  drupal_add_library('mymodule', 'mylibrary');
}

You would expect that the path "sites/all/modules/mymodule/mylibrary.js" would be added to the page, but instead "1ites/all/modules/mymodule/mylibrary.js" is. You can change the version number to "2.0" and see that the path becomes "2ites/all/modules/mymodule/mylibrary.js".

This problem stems from this bit of code in drupal_get_library:

        $module_libraries[$key] += array(
          'dependencies' => array(),
          'js' => array(),
          'css' => array(),
        );
        foreach ($module_libraries[$key]['js'] as $file => $options) {
          $module_libraries[$key]['js'][$file]['version'] = $module_libraries[$key]['version'];
        }

If $file is not an array, but a string, then setting "version" actually just replaces the first letter of the string.

Comments

quicksketch’s picture

Oh, and the quick workaround for developers experiencing this problem, just use the long-form syntax in hook_library for the 'js' file:

function mymodule_library() {
  $libraries['mylibrary'] = array(
    'title' => 'My Module: My Library',
    'version' => '1.0',
    'js' => array(
      drupal_get_path('module', 'mymodule') . '/mylibrary.js' => array('group' => JS_DEFAULT),
    ),
  );

  return $libraries;
}

Adding the => array('group' => JS_DEFAULT) makes it so that the library is defined as an array as drupal_get_library() expects. Seems like the most sane solution would be to allow modules to use the shorthand syntax in hook_library(), but then convert it to a consistent syntax so we don't have these messy confusions.

tstoeckler’s picture

We stumbled on this in Libraries API.
See libraries_prepare_files(), specifically: http://drupalcode.org/project/libraries.git/blob/623d0058df35cd57d93b5a8...

larowlan’s picture

Assigned: Unassigned » larowlan

hit this today in a 7.x project.
thanks to @boztek for pointing me at this.

larowlan’s picture

Assigned: larowlan » Unassigned
Status: Active » Needs review
Issue tags: +Needs backport to D7
StatusFileSize
new2.9 KB
new2.31 KB

First a fail patch, then a pass.
Drupal 8 - 'Now with 70% more magical ponies, llamas and unicorns'™.
(We already have llamas and unicorns in edit module).

Adding backport tag.

nick_schuch’s picture

Status: Needs review » Reviewed & tested by the community

Super bazaar but reproducible in both the testing larowlan has provided and my manual testing via quicksketch's instructions.

I cannot fault this. If anyone has any objections (not with the ponies!) then move back to "Needs work" etc.

quicksketch’s picture

Thanks @larowlan. Nice and simple solution. +1

nick_schuch’s picture

StatusFileSize
new819 bytes

This is the basic module that I setup to test this functionality (if others wish to also test).

quicksketch’s picture

@nick_schuch: What I usually like to do is comment out or remove the "hidden: true" line in test modules so I can enable them directly in the normal UI. There are all kinds of test modules intended for automated testing that are also useful for manual testing.

nick_schuch’s picture

That also works. Cheers!

xjm’s picture

Issue tags: +Quick fix

#4 is the patch (not #7).

webchick’s picture

Status: Reviewed & tested by the community » Needs work

So I've nothing against ponies, per se, but it really needs to be a whole lot clearer to people coming at this many months from now trying to figure out why their tests are failing about what exactly this test was aiming to be testing in the first place. :P So augmenting this with some comments or something that explains this better is needed.

Then my follow-up stupid question to that would be, "Why do we allow more than one way to do this in the first place?" That just seems confusing and error-prone (as evidenced by this issue). It seems like it should always be an array, then nothing ever gets clobbered. No?

larowlan’s picture

Thanks @webchick - will tidy up comments etc tomorrow and tone down the goofiness.
Reasons why you shouldn't ask an 11 year old to name a plugin.

larowlan’s picture

Status: Needs work » Needs review
StatusFileSize
new3.47 KB
new4.15 KB

Sorry Tony, you had to go!

quicksketch’s picture

Status: Needs review » Reviewed & tested by the community

New version looks good too.

Regarding the short-hand format... I think it's a fine convenience. The syntax for JS/CSS is so crazy verbose I'm happy that there's a short version that just gets something working, then later you can add the extra options for changing your file weight if that's important to you. Although we're talking about adding JS as part of library_info hooks here, we have the same shorthand syntax for #attached as well. Which would you rather write?

$form['foo']['#attached'] = array(
  'js' => array($module_path . '/mymodule.js'),
);

$form['foo']['#attached'] = array(
  'js' => array($module_path . '/mymodule.js' => array()),
);

In any case, keeping the short syntax for now makes this patch completely backportable to D7, which suffers the same problem.

alexpott’s picture

Version: 8.x-dev » 7.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)
Issue tags: -Quick fix

Committed f6b150a and pushed to 8.x. Thanks!

dcam’s picture

Status: Patch (to be ported) » Needs review
StatusFileSize
new2.67 KB
new1.82 KB

Backported #13 to D7.

Status: Needs review » Needs work

The last submitted patch, 1396892-16-js-libraries.patch, failed testing.

dcam’s picture

Status: Needs work » Needs review
StatusFileSize
new3.23 KB
new2.38 KB

Let's try a backport again, this time with the javascript file actually added to the patch.

mgifford’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

No longer applies.

dcam’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new3.23 KB

Rerolled #18.

  • alexpott committed f6b150a on 8.3.x
    Issue #1396892 by larowlan, nick_schuch | quicksketch: Fixed...

  • alexpott committed f6b150a on 8.3.x
    Issue #1396892 by larowlan, nick_schuch | quicksketch: Fixed...

  • alexpott committed f6b150a on 8.4.x
    Issue #1396892 by larowlan, nick_schuch | quicksketch: Fixed...

  • alexpott committed f6b150a on 8.4.x
    Issue #1396892 by larowlan, nick_schuch | quicksketch: Fixed...

Status: Needs review » Closed (outdated)

Automatically closed because Drupal 7 security and bugfix support has ended as of 5 January 2025. If the issue verifiably applies to later versions, please reopen with details and update the version.