There is a growing sentiment in the performance community to render pages as fast as possible, and avoid any blocking JS in the head. Moving JS to the bottom of an HTML document has long been a best practice, but Modernizr was often considered one of the few exceptions to this rule.

I think it's responsible for us to offer some method of avoiding the blocking-JS-in-head problem. In my opinion the option to set defer on the script tag is more attractive than changing drupal_add_js() scope; it's just a bit you have to flip and nothing more.

CommentFileSizeAuthor
#2 2252899-2-defer-modernizr.patch1.91 KBrupl

Comments

rupl’s picture

rupl’s picture

Status: Active » Needs review
StatusFileSize
new1.91 KB

Here's the patch. It defers by default, per discussion on GitHub in comment #1.

You should see markup similar to the following after applying the patch:

<script type="text/javascript" defer="defer" src="http://modernizr/sites/all/libraries/modernizr/modernizr.min.js?n5axzy"></script>

If you visit /admin/config/development/modernizr/settings there is an option to switch back to synchronous loading, and if you select it the defer attribute should be removed entirely.

  • rupl committed d1dc06a on 7.x-3.x
    Issue #2252899 by rupl: add option to defer. Set it to defer by default.
    
rupl’s picture

Status: Needs review » Fixed

Committed to dev!

  • rupl committed bcb1d35 on 7.x-3.x
    Follow up #2252899 by rupl: set defer to TRUE by default.
    

  • rupl committed 6f0ad74 on 7.x-3.x
    Issue #2252899 and #2262815 by rupl: delete modernizr_type on uninstall.
    

Status: Fixed » Closed (fixed)

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

rupl’s picture

Status: Closed (fixed) » Active

It was brought to my attention that using this new defer option along with our Drupal-powered Modernizr.load() results in an error because you can't defer inline scripts.

So the reference to modernizr.js is deferred, but the Modernizr.load() code is *not* deferred, runs immediately, and produces an Uncaught ReferenceError: Modernizr is not defined.

I think the quickest fix might be to detect if hook_modernizr_load() produces anything, and if it is being used then we manually remove the defer attribute. A longer-term fix would be to cache the Modernizr.load() code in a Drupal-cached file (similar to aggregates) so that both scripts can be deferred.

More info about defer available on MDN.

rupl’s picture

Category: Feature request » Bug report
Priority: Normal » Major

Reclassifying issue to match current situation.

katzmo’s picture

Since modernizr is used for browser compatibility IMHO the default settings should work for as many use cases as possible, especially in old browsers, and not break existing installations. Defer does both. (See http://caniuse.com/#search=defer and Known Issues for browser compatibility)

So why not keep 'synchronous' as default setting? If you don't need things like html5shiv and rather load modernizr asynchronous, then you may change your settings accordingly!

rupl’s picture

You're right. I should have fixed this a month ago anyway when I discovered the problem in comment #8.

  • rupl committed b84a2ff on 7.x-3.x
    Issue #2252899 by rupl, katzmo: Update default settings for script tag
    
marcvangend’s picture

Status: Active » Fixed

I completely agree with #10. This fix would have saved me 2 hours of figuring out why the html5shiv wasn't doing anything in IE8.

This issue is fixed I guess. A new release would be appreciated!

Status: Fixed » Closed (fixed)

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

rupl’s picture

Version: 7.x-3.x-dev » 7.x-3.4

My sincere apologies :( There is a new release now.

edit: https://www.drupal.org/node/2403197