Make WordPress Core


Ignore:
Timestamp:
10/13/2023 06:44:12 PM (14 months ago)
Author:
westonruter
Message:

Script Loader: Move delayed head script to footer when there is a blocking footer dependent.

This prevents a performance regression when a blocking script is enqueued in the footer which depends on a delayed script in the head (with async or defer). In order to preserve the execution order, a delayed dependency must fall back to blocking when there is a blocking dependent. But since it was originally delayed (and thus executes similarly to a footer script), it does not need to be in the head and can be moved to the footer. This prevents blocking the critical rendering path.

Props adamsilverstein, westonruter, flixos90.
Fixes #59599.
See #12009.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-scripts.php

    r56687 r56933  
    233233
    234234    /**
     235     * Checks whether all dependents of a given handle are in the footer.
     236     *
     237     * If there are no dependents, this is considered the same as if all dependents were in the footer.
     238     *
     239     * @since 6.4.0
     240     *
     241     * @param string $handle Script handle.
     242     * @return bool Whether all dependents are in the footer.
     243     */
     244    private function are_all_dependents_in_footer( $handle ) {
     245        foreach ( $this->get_dependents( $handle ) as $dep ) {
     246            if ( isset( $this->groups[ $dep ] ) && 0 === $this->groups[ $dep ] ) {
     247                return false;
     248            }
     249        }
     250        return true;
     251    }
     252
     253    /**
    235254     * Processes a script dependency.
    236255     *
     
    280299        if ( ! $this->is_delayed_strategy( $intended_strategy ) ) {
    281300            $intended_strategy = '';
     301        }
     302
     303        /*
     304         * Move this script to the footer if:
     305         * 1. The script is in the header group.
     306         * 2. The current output is the header.
     307         * 3. The intended strategy is delayed.
     308         * 4. The actual strategy is not delayed.
     309         * 5. All dependent scripts are in the footer.
     310         */
     311        if (
     312            0 === $group &&
     313            0 === $this->groups[ $handle ] &&
     314            $intended_strategy &&
     315            ! $this->is_delayed_strategy( $strategy ) &&
     316            $this->are_all_dependents_in_footer( $handle )
     317        ) {
     318            $this->in_footer[] = $handle;
     319            return false;
    282320        }
    283321
Note: See TracChangeset for help on using the changeset viewer.