[wp-trac] [WordPress Trac] #12009: Add support for HTML 5 "async" and "defer" attributes

WordPress Trac noreply at wordpress.org
Fri May 12 21:14:53 UTC 2023


#12009: Add support for HTML 5 "async" and "defer" attributes
-------------------------------------------------+-------------------------
 Reporter:  Otto42                               |       Owner:  10upsimon
     Type:  enhancement                          |      Status:  assigned
 Priority:  high                                 |   Milestone:  6.3
Component:  Script Loader                        |     Version:  4.6
 Severity:  normal                               |  Resolution:
 Keywords:  has-patch has-unit-tests 2nd-        |     Focuses:
  opinion                                        |  performance
-------------------------------------------------+-------------------------

Comment (by joemcgill):

 @azaozz, it seems like the crux of your concern is not whether WP should
 support `async` scripts, but instead whether this should be part of the
 Script loader API or handled by some other means. Forgive me if I’m
 misunderstanding.

 > True. However, it doesn't make sense to use that API just to output a
 `<script>` tag imho, i.e. waste a bit of resources "just because why not"
 :)

 I feel pretty strongly that `wp_register_script` and `wp_enqueue_script`
 (and the Script loader that these rely on) are the primary API used in the
 WP ecosystem for printing any kind of script, regardless of whether they
 have dependencies. In any case, there are several reasons to support
 `async` specifically via these APIs rather than requiring developers use
 other manual processes:

 - The Script loader reduces the amount of code developers need to use to
 print a script. If not using the Script loader, you’d have to manually
 print the `<script>` tag yourself at `wp_head` or `wp_footer`, which would
 mean there is no standard way to attach inline scripts.
 - Using the Scripts API allows other plugins to dequeue an `async` script
 in the standard way. Otherwise, the only way to prevent the script from
 being printed is to hunt around for the function that prints the script,
 and pass it to `remove_action()`, where hopefully a closure isn’t used
 and/or a method’s class instance variable is available.
 - There are already over
 [https://wpdirectory.net/search/01H06E357YYF6M76GHJJHJV99Q 3,000] examples
 of plugins adding `async` scripts to the page. Many of which resort to
 manually printing the script tag specifically because they can’t use
 `wp_enqueue_script()`. See this
 [https://plugins.trac.wordpress.org/browser/call-now-
 button/trunk/src/renderers/cloud/class-cloudrenderer.php#L72 inline
 comment] example.

 Additionally, `async` scripts can absolutely support dependencies. I’m
 adding several examples below. As an aside, registering `async` scripts
 with dependencies (even if the load order cannot be assumed) allows both
 first-party and third-party projects to ensure all dependencies are
 included in the markup whenever the single script relying on those
 dependencies is enqueued.

 - AMP scripts are all `async`, and components all
 [https://github.com/ampproject/amp-
 wp/blob/c629ad2967b3bc80d10f9d3395935747e7a413a5/includes/amp-helper-
 functions.php#L1007-L1012 depend on amp-runtime `async` script].
 - WPFront Scroll Top registers a script and
 [https://plugins.trac.wordpress.org/browser/wpfront-scroll-
 top/trunk/classes/class-wpfront-scroll-top.php#L238 adds `async`] to it.
 This script has [https://plugins.trac.wordpress.org/browser/wpfront-
 scroll-top/trunk/classes/class-wpfront-scroll-top.php#L146 a blocking
 dependency on jQuery].
 - Also, the To Top plugin [https://plugins.trac.wordpress.org/browser/to-
 top/trunk/public/class-to-top-public.php#L105 adds `async`] to a script
 which has [https://plugins.trac.wordpress.org/browser/social-pug/trunk/inc
 /class-asset-loader.php#L89 a blocking dependency on jQuery].
 - Grow Social [https://plugins.trac.wordpress.org/browser/social-
 pug/trunk/inc/class-asset-loader.php#L47 adds `async`] to script which
 also has a [https://plugins.trac.wordpress.org/browser/social-
 pug/trunk/inc/class-asset-loader.php#L89 blocking dependency on jQuery].
 - The Scroll Top plugin adds `async` script which also
 [https://plugins.trac.wordpress.org/browser/scroll-
 top/trunk/inc/functions.php#L61 has blocking dependency on jQuery].
 - (Not in a plugin, but Glitch of `async` library demo: https://async-
 library-script-loading-demo.glitch.me/)

 Async scripts are already being used with before/after inline scripts.
 Using the Scripts API allows inline scripts to be easily attached,
 including by other plugins. See the following:

 - WooCommerce [https://github.com/woocommerce/woocommerce-google-
 analytics-
 integration/blob/fbcf24f01d3767eb984fe46a0582a03b6216bad5/includes/class-
 wc-google-analytics.php#L711-L726 adds `async`] to a google-tag-manager
 script. It also [https://github.com/woocommerce/woocommerce-google-
 analytics-
 integration/blob/fbcf24f01d3767eb984fe46a0582a03b6216bad5/includes/class-
 wc-google-gtag-js.php#L326 registers a dependency] for this script (which
 actually turns out to be [https://github.com/woocommerce/woocommerce-
 google-analytics-
 integration/blob/fbcf24f01d3767eb984fe46a0582a03b6216bad5/includes/class-
 wc-abstract-google-analytics-js.php#L52-L65 another inline script]) as
 well as [https://github.com/woocommerce/woocommerce-google-analytics-
 integration/blob/fbcf24f01d3767eb984fe46a0582a03b6216bad5/includes/class-
 wc-google-gtag-js.php#L327 an inline script].
 - Smush adds [https://plugins.trac.wordpress.org/browser/wp-
 smushit/trunk/core/modules/class-lazy.php#L247 adds `async`] to a script,
 and then conditionally [https://plugins.trac.wordpress.org/browser/wp-
 smushit/trunk/core/modules/class-lazy.php#L279 adds (before) inline
 scripts] based on whether other features are active.
 - Cookie Notice & Compliance for GDPR / CCPA (cookie-notice)
 [https://plugins.trac.wordpress.org/browser/cookie-
 notice/trunk/includes/frontend.php#L467 adds `async`] to a script and adds
 an [https://plugins.trac.wordpress.org/browser/cookie-
 notice/trunk/includes/frontend.php#L452 inline before script].
 - Advanced Responsive Video Embedder [https://github.com/nextgenthemes
 /advanced-responsive-video-
 embedder/blob/cb4c053298e795686dcbd5c450a8a2da5fea1625/php/Admin
 /functions-admin.php#L279-L289 adds `async` script with inline before
 script].
 - Crisp
 [https://plugins.trac.wordpress.org/browser/crisp/trunk/crisp.php#L240
 adds `async` script with before inline script].
 - simple-facebook-twitter-widget
 [https://plugins.trac.wordpress.org/browser/simple-facebook-twitter-
 widget/trunk/simple-facebook-page-plugin.php#L270 adds `async`] script
 which has [https://plugins.trac.wordpress.org/browser/simple-facebook-
 twitter-widget/trunk/simple-facebook-page-plugin.php#L249 inline script]
 added via `wp_localize_script()`

 Hopefully, these are helpful real world examples. Props to @westonruter
 for helping me pull these examples together. I also want to address a last
 point:

 > If all cases for using `async` are only for stand-alone scripts there is
 no point to make Script loader more complex and slower for all other
 scripts.

 The way that we’ve implemented logic to resolve loading strategy conflicts
 in the dependency tree is already in place for `defer` and `async`.
 Removing `async` logic will not make any meaningful difference in
 performance or complexity.

 Based on all of this, I propose the following next steps:
 1. We agree to support `async` scripts in the script loader with
 dependencies (this is already implemented, but we can address specifics in
 the PR).
 2. We iron out remaining issues for how inline scripts are handled for
 defer and `async` scripts.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/12009#comment:111>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list