[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