Make WordPress Core

Opened 16 months ago

Last modified 5 months ago

#61657 new defect (bug)

Script "in_footer" => false with "defer" will make all dependencies that are not deferred load in head

Reported by: kkmuffme's profile kkmuffme Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version:
Component: Script Loader Keywords: reporter-feedback
Focuses: performance Cc:

Description

wp_register_script( 'foo', get_template_directory_uri() . '/foo.js', array(), '1.0.0', array( 'in_footer' => true ) );

wp_register_script( 'bar', get_template_directory_uri() . '/bar.js', array( 'foo' ), '1.0.0', array( 'in_footer' => false, 'strategy' => 'defer' ) );

This will output both scripts in the head.
However, this isn't necessary and leads to worse performance.
Because "bar" which isn't loaded in footer, is loaded using the "defer" attribute, the browser would execute it after "foo", even though it's in the HTML before it.

The only exception is browsers that do not support the "defer" attribute (which currently there are none to consider https://caniuse.com/script-defer), where this wouldn't work.

A practical use case is wp-admin: these pages are usually not page cached, and it takes considerable amount of time from the time the header is flushed to the browser to the time PHP generated the page up to the footer and flushed it to the browser.
This time can be used by the browser to download these JS files in the head; the "defer" attribute ensures it will only execute once the whole page has loaded.

Secondly, I suggest that if a script that has footer false with defer and an "after" inline script is added to it, it will not just drop the "defer" but instead convert the footer false to footer true internally (since this was the original intention of the execution point when it was registered)

Change History (1)

#1 @westonruter
5 months ago

  • Focuses performance added
  • Keywords reporter-feedback added

I think I understand. The current logic is such that if foo is printed in the footer, and bar is printed in the head, if bar depends on foo then foo must be moved to the head so as to ensure the correct load order. But if bar is has defer then it will always load after blocking foo anyway, so it can remain in the head.

Are there any cases you're aware of where this is happening? I wonder if this is an edge case that isn't worth worrying about.

However, if someone were to add the defer loading strategy to foo, then at this point bar would have to continue to be moved to the head since then they would load in the wrong dependency order after the document has loaded.

Secondly, I suggest that if a script that has footer false with defer and an "after" inline script is added to it, it will not just drop the "defer" but instead convert the footer false to footer true internally (since this was the original intention of the execution point when it was registered)

I'm not sure I understand. If a deferred script has an after inline script, then defer has to be removed for safety to ensure that the inline script is able to access whatever globals that the script may be defining.

Note: See TracTickets for help on using tickets.