Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement script loading strategies (async & defer) in core, themes, and plugins #786

Open
7 of 10 tasks
westonruter opened this issue Jul 18, 2023 · 12 comments
Open
7 of 10 tasks
Assignees
Labels
Gutenberg Plugin Issue relates to work on Gutenberg only [Issue] Overview Provides an overview of a specific project WP Core Work relates to inclusion in WP Core only

Comments

@westonruter
Copy link
Member

westonruter commented Jul 18, 2023

Feature Description

Now that Script Loading Strategies (async and defer) have landed in WordPress 6.3 (see Core-12009 and Dev Note), the task now is to take advantage of this new performance capability in core, themes, and plugins. This is a tracking issue to that end.

6.4 Milestone

Future Release

  • Find opportunities for async/defer scripts in the WP Admin (Core-59301).
  • Move jQuery and other dependencies to footer if there aren't any non-footer dependents? (Not feasible.)

Ecosystem

  • Reach out to theme and plugin authors using legacy means of adding async & defer to adopt the new API.
  • Find new opportunities for using script loading strategies in popular themes & plugins.
@westonruter westonruter added the [Issue] Overview Provides an overview of a specific project label Jul 18, 2023
@felixarntz felixarntz added this to the WordPress 6.4 milestone Jul 19, 2023
@felixarntz felixarntz added WP Core Work relates to inclusion in WP Core only Gutenberg Plugin Issue relates to work on Gutenberg only labels Jul 19, 2023
@westonruter westonruter self-assigned this Jul 28, 2023
@joemcgill
Copy link
Member

From today's bug scrub, is this something worth looking into? https://core.trac.wordpress.org/ticket/58810

@felixarntz
Copy link
Member

@westonruter You have a point in the issue description on "Move jQuery and other dependencies to footer if there aren't any non-footer dependents?". While I would love to do this, I think unless we find a very clever solution (I can't think of at the moment), we can't reasonably do that, since jQuery is so heavily used on WordPress sites, in lots of unrecommended ways, like inline JS directly injected into e.g. post content that assumes that jQuery is loaded. So I think deferring jQuery will cause a ton of breakage, unless we find a reliable way to ensure it's not used anywhere on the page (even outside of the WP Scripts API, that's the important bit to consider additionally on this one).

@westonruter
Copy link
Member Author

@felixarntz yeah, I had similar concerns when I added it to the list. It came to mind because I saw WooCommerce adding scripts to the footer, but since they depended on jQuery it got added to the head. I agree that it is not really feasible to do. I'll cross it out.

@westonruter
Copy link
Member Author

  • Move theme scripts from footer to head and add defer.

I just tried this with Twenty Seventeen:

diff --git a/src/wp-content/themes/twentyseventeen/functions.php b/src/wp-content/themes/twentyseventeen/functions.php
index 83964158b1..a31adfcca9 100644
--- a/src/wp-content/themes/twentyseventeen/functions.php
+++ b/src/wp-content/themes/twentyseventeen/functions.php
@@ -447,6 +447,11 @@ add_action( 'wp_head', 'twentyseventeen_colors_css_wrap' );
  * Enqueues scripts and styles.
  */
 function twentyseventeen_scripts() {
+	$args = array(
+		'in_footer' => isset( $_GET['with-defer'] ) ? false : true,
+		'strategy' => isset( $_GET['with-defer'] ) ? 'defer' : null,
+	);
+
 	// Add custom fonts, used in the main stylesheet.
 	$font_version = ( 0 === strpos( (string) twentyseventeen_fonts_url(), get_template_directory_uri() . '/' ) ) ? '20230328' : null;
 	wp_enqueue_style( 'twentyseventeen-fonts', twentyseventeen_fonts_url(), array(), $font_version );
@@ -479,14 +484,14 @@ function twentyseventeen_scripts() {
 	// Skip-link fix is no longer enqueued by default.
 	wp_register_script( 'twentyseventeen-skip-link-focus-fix', get_theme_file_uri( '/assets/js/skip-link-focus-fix.js' ), array(), '20161114', true );
 
-	wp_enqueue_script( 'twentyseventeen-global', get_theme_file_uri( '/assets/js/global.js' ), array( 'jquery' ), '20211130', true );
+	wp_enqueue_script( 'twentyseventeen-global', get_theme_file_uri( '/assets/js/global.js' ), array( 'jquery' ), '20211130', $args );
 
 	$twentyseventeen_l10n = array(
 		'quote' => twentyseventeen_get_svg( array( 'icon' => 'quote-right' ) ),
 	);
 
 	if ( has_nav_menu( 'top' ) ) {
-		wp_enqueue_script( 'twentyseventeen-navigation', get_theme_file_uri( '/assets/js/navigation.js' ), array( 'jquery' ), '20210122', true );
+		wp_enqueue_script( 'twentyseventeen-navigation', get_theme_file_uri( '/assets/js/navigation.js' ), array( 'jquery' ), '20210122', $args );
 		$twentyseventeen_l10n['expand']   = __( 'Expand child menu', 'twentyseventeen' );
 		$twentyseventeen_l10n['collapse'] = __( 'Collapse child menu', 'twentyseventeen' );
 		$twentyseventeen_l10n['icon']     = twentyseventeen_get_svg(
@@ -499,7 +504,7 @@ function twentyseventeen_scripts() {
 
 	wp_localize_script( 'twentyseventeen-global', 'twentyseventeenScreenReaderText', $twentyseventeen_l10n );
 
-	wp_enqueue_script( 'jquery-scrollto', get_theme_file_uri( '/assets/js/jquery.scrollTo.js' ), array( 'jquery' ), '2.1.3', true );
+	wp_enqueue_script( 'jquery-scrollto', get_theme_file_uri( '/assets/js/jquery.scrollTo.js' ), array( 'jquery' ), '2.1.3', $args );
 
 	if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) {
 		wp_enqueue_script( 'comment-reply' );

With SCRIPT_DEBUG disabled on my wordpress-develop environment, I tested:

$ npm run research -- benchmark-web-vitals -u http://localhost:8889/ -n 100 -o csv
> research
> ./cli/run.mjs benchmark-web-vitals -u http://localhost:8889/ -n 100 -o csv

URL,http://localhost:8889/
Success Rate,100%
FCP (median),82.95
LCP (median),82.95
TTFB (median),16.9
LCP-TTFB (median),65.15

And:

$ npm run research -- benchmark-web-vitals -u http://localhost:8889/?with-defer -n 100 -o csv
> research
> ./cli/run.mjs benchmark-web-vitals -u http://localhost:8889/?with-defer -n 100 -o csv

URL,http://localhost:8889/?with-defer
Success Rate,100%
FCP (median),94.3
LCP (median),94.3
TTFB (median),28.15
LCP-TTFB (median),65.25

So moving footer scripts to the head and making them defer is actually slightly worse for performance for Twenty Seventeen (~0.15%).

I also tried with Fast 3G network emulation:

$ npm run research -- benchmark-web-vitals -u http://localhost:8889/ -n 100 -o csv

> research
> ./cli/run.mjs benchmark-web-vitals -u http://localhost:8889/ -n 100 -c Fast 3G -o csv

URL,http://localhost:8889/
Success Rate,100%
FCP (median),744.2
LCP (median),744.4
TTFB (median),17.1
LCP-TTFB (median),728.2
$ npm run research -- benchmark-web-vitals -u http://localhost:8889/?with-defer -n 100 -o csv

> research
> ./cli/run.mjs benchmark-web-vitals -u http://localhost:8889/?with-defer -n 100 -c Fast 3G -o csv

URL,http://localhost:8889/?with-defer
Success Rate,100%
FCP (median),1339.6
LCP (median),1339.6
TTFB (median),614.6
LCP-TTFB (median),725

And here using defer is only 0.43% faster.

So it doesn't seem really worthwhile for Twenty Seventeen.

@joemcgill
Copy link
Member

joemcgill commented Aug 28, 2023

@felixarntz yeah, I had similar concerns when I added it to the list. It came to mind because I saw WooCommerce adding scripts to the footer, but since they depended on jQuery it got added to the head. I agree that it is not really feasible to do. I'll cross it out.

Just saw this question come up in WP Slack. I think it is worth us having a ticket to track this specific line of questions, even if we still determine that it's unfeasible for core, so individual sites can find direction about how to opt into supporting jquery as a deferred or footer loaded script. Also, we could better explain why it's not feasible to fix in core. @westonruter do you already have any shareable info we could add?

@felixarntz
Copy link
Member

@westonruter Can you provide an update on the remaining points in the issue description where they're at?

Taking a glance, the first two remaining ones may still be subject to the 6.4 beta cutoff deadline, so maybe we should prioritize them? Are there tickets already, or what is left to do?

@westonruter
Copy link
Member Author

@felixarntz:

Themes

In regards to themes, my findings for Twenty Seventeen are in #786 (comment), and not finding any improvement to using async/defer in Twenty Seventeen kinda took the wind out of my sails. Nevertheless, all/both block themes (TT2 and TT3) have been accounted for by adopting defer for all block view scripts (Core-59115). I'll check the other themes and see if there are any clear wins.

Aside, current install counts for core themes:

Theme Count
2023 1,000,000+
2022 600,000+
2021 700,000+
2020 500,000+
2019 200,000+
2017 600,000+
2016 100,000+
2015 100,000+
2014 90,000+
2013 40,000+
2012 90,000+
2011 100,000+
2010 80,000+

Admin

I've filed Core-59301 to further investigate the admin. However, since admin pages are typically visited by a user multiple times they'll have the assets already in the browser cache, making optimization of the loading order less impactful than optimizing frontend responses for many first-time visits. Similarly, the admin would generally have a tiny fraction of the top level navigations on a given site compared to the frontend. For these reasons, I don't think we should prioritize too high the optimization of the admin until we're sure that the frontend has been fully optimized.

@felixarntz
Copy link
Member

felixarntz commented Sep 6, 2023

Thanks @westonruter.

Regarding the classic default themes, I wonder if we should still aim to make the changes just to set a good example on the loading strategies in general. I could see how they don't make a big difference in default themes because they don't typically load a ton of JS, but it may still set a good example, and other "heavier" themes may see a larger benefit. So I'm thinking as long as there aren't any adverse effects, it may still be good to raise a ticket for that to update default themes' frontend scripts to use the loading strategies. WDYT?

Regarding WP Admin, makes sense to me not to prioritize it too much. I guess we can keep that ticket open for now, though we might also argue based on your observations that this is not worth investing in at all and closing as wontfix or maybelater. Even then I think it's good to have opened this ticket just for historic purposes. 👍

@westonruter
Copy link
Member Author

@felixarntz:

Regarding the classic default themes, I wonder if we should still aim to make the changes just to set a good example on the loading strategies in general. I could see how they don't make a big difference in default themes because they don't typically load a ton of JS, but it may still set a good example, and other "heavier" themes may see a larger benefit. So I'm thinking as long as there aren't any adverse effects, it may still be good to raise a ticket for that to update default themes' frontend scripts to use the loading strategies. WDYT?

Here's the ticket: Core-59316

And here's a PR which is ready for initial review: WordPress/wordpress-develop#5170

@westonruter
Copy link
Member Author

  • Find opportunities for async/defer scripts in the WP Admin (Core-59301).
  • Reach out to theme and plugin authors using legacy means of adding async & defer to adopt the new API.
  • Find new opportunities for using script loading strategies in popular themes & plugins.

Shall we split these out into separate issues and close this one as completed for 6.4? The first already has a Trac ticket.

@felixarntz
Copy link
Member

@westonruter Since this is an overview issue, I think it's best to keep everything under here. I'd say we can remove the 6.4 milestone from this issue though, since not everything tracked by this issue is even subject to core releases.

@westonruter westonruter removed this from the WordPress 6.4 milestone Sep 21, 2023
@joemcgill
Copy link
Member

On a few other overview issues, I've started adding separate headers for the stuff that is targeted for this release and for stuff that will land in a future release (example). Doing something similar here might be helpful, but I agree that it's best to keep everything related to this effort in one place rather than in separate issues that are milestone specific.

@sstopfer sstopfer moved this to In Progress 🚧 in WP Performance 2024 May 26, 2024
@sstopfer sstopfer added [Focus] JS & CSS and removed [Focus] JS & CSS WP Core Work relates to inclusion in WP Core only Gutenberg Plugin Issue relates to work on Gutenberg only labels May 26, 2024
@sstopfer sstopfer added WP Core Work relates to inclusion in WP Core only Gutenberg Plugin Issue relates to work on Gutenberg only labels May 26, 2024
@sstopfer sstopfer moved this from In Progress 🚧 to Not Started/Backlog 📆 in WP Performance 2024 Jul 16, 2024
@sstopfer sstopfer moved this from Not Started/Backlog 📆 to On Hold ⛔ in WP Performance 2024 Jul 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Gutenberg Plugin Issue relates to work on Gutenberg only [Issue] Overview Provides an overview of a specific project WP Core Work relates to inclusion in WP Core only
Projects
Status: On Hold ⛔
Development

No branches or pull requests

4 participants