Make WordPress Core

Changeset 64320


Ignore:
Timestamp:
10/13/2026 04:12:29 AM (6 days ago)
Author:
westonruter
Message:

Script Loader: Disable script/style concatenation by default.

Scripts and styles in the admin and on the login screen are no longer concatenated by default. When the CONCATENATE_SCRIPTS constant is not defined, wp_should_concatenate_admin_scripts() now returns false, so load-scripts.php and load-styles.php are only used when a site opts in with define( 'CONCATENATE_SCRIPTS', true ). This is the next step toward retiring concatenation. It also puts into effect the prefetching of the admin's assets added in r64120, which only applies when concatenation is off. With an empty browser cache, logging in and then opening the Dashboard, the Posts list and the block editor was measured to be faster this way than with concatenation on.

TinyMCE is now always registered as two separate files instead of the prebuilt wp-tinymce.js bundle: TinyMCE core and the compat3x plugin. The bundle was registered only when scripts were both concatenated and compressed, and since r43580 and r44651 the $compress_scripts global has not compressed anything, so the registration no longer depends on either. The block editor loads TinyMCE on every screen but initializes it only when a Classic block is edited, so it now downloads 369 KB for the two files instead of 671 KB for the bundle, which also holds the theme and all 22 plugins. When TinyMCE is initialized, in the classic editor or for a Classic block, it now requests them itself and takes longer to become ready, a cost deemed acceptable since the role TinyMCE is increasingly diminished. A site can still register the bundle under the wp-tinymce handle. The unused second parameter of wp_register_tinymce_scripts() is deprecated.

Developed in ​https://github.com/WordPress/wordpress-develop/pull/13090.
Follow-up to r43580, r44114, r44651, r64120.

Props adnan007, westonruter.
See #57548, #66053.

Location:
trunk
Files:
4 edited

Legend:

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

    r64304 r64320  
    15421542
    15431543                $wp_scripts->remove( 'wp-tinymce' );
    1544                 wp_register_tinymce_scripts( $wp_scripts, true );
     1544                wp_register_tinymce_scripts( $wp_scripts );
    15451545        }
    15461546
  • trunk/src/wp-includes/script-loader.php

    r64235 r64320  
    55 * Several constants are used to manage the loading, concatenating and compression of scripts and CSS:
    66 * define('SCRIPT_DEBUG', true); loads the development (non-minified) versions of all scripts and CSS, and disables compression and concatenation,
    7  * define('CONCATENATE_SCRIPTS', false); disables compression and concatenation of scripts and CSS,
     7 * define('CONCATENATE_SCRIPTS', true); enables concatenation of scripts and CSS in the admin and on the login screen (disabled by default),
    88 * define('COMPRESS_SCRIPTS', false); disables compression of scripts,
    99 * define('COMPRESS_CSS', false); disables compression of CSS,
    … …  
    3838 * Registers TinyMCE scripts.
    3939 *
     40 * TinyMCE core and the compat3x plugin are registered as separate files. TinyMCE loads its theme
     41 * and any other plugins itself when an editor is initialized. The `wp-tinymce.js` bundle of all of
     42 * them is no longer registered, but it can still be registered in their place under the
     43 * `wp-tinymce` handle.
     44 *
    4045 * @since 5.0.0
     46 * @since 7.2.0 The `wp-tinymce.js` bundle is no longer registered, regardless of whether scripts
     47 *              are concatenated or compressed.
     48 * @since 7.2.0 The `$force_uncompressed` parameter was deprecated and renamed to `$deprecated`.
    4149 *
    4250 * @global string $tinymce_version
    43  * @global bool   $concatenate_scripts
    44  * @global bool   $compress_scripts
    45  *
    46  * @param WP_Scripts $scripts            WP_Scripts object.
    47  * @param bool       $force_uncompressed Whether to forcibly prevent gzip compression. Default false.
    48  */
    49 function wp_register_tinymce_scripts( $scripts, $force_uncompressed = false ) {
    50         global $tinymce_version, $concatenate_scripts, $compress_scripts;
     51 *
     52 * @param WP_Scripts $scripts    WP_Scripts object.
     53 * @param bool       $deprecated Not used.
     54 *
     55 * @phpstan-param false $deprecated
     56 */
     57function wp_register_tinymce_scripts( $scripts, $deprecated = false ): void {
     58        global $tinymce_version;
     59
     60        if ( false !== $deprecated ) {
     61                _deprecated_argument( __FUNCTION__, '7.2.0' );
     62        }
    5163
    5264        $suffix     = wp_scripts_get_suffix();
    5365        $dev_suffix = wp_scripts_get_suffix( 'dev' );
    5466
     67        /*
     68         * This no longer depends on the concatenation settings, but it is where an admin screen has
     69         * settled them until now, which the 'wp_should_concatenate_admin_scripts' filter documents.
     70         */
    5571        script_concat_settings();
    5672
    57         $compressed = $compress_scripts && $concatenate_scripts && ! $force_uncompressed;
    58 
    59         /*
    60          * Load tinymce.js when running from /src, otherwise load wp-tinymce.js (in production)
    61          * or tinymce.min.js (when SCRIPT_DEBUG is true).
    62          */
    63         if ( $compressed ) {
    64                 $scripts->add( 'wp-tinymce', includes_url( 'js/tinymce/' ) . 'wp-tinymce.js', array(), $tinymce_version );
    65         } else {
    66                 $scripts->add( 'wp-tinymce-root', includes_url( 'js/tinymce/' ) . "tinymce$dev_suffix.js", array(), $tinymce_version );
    67                 $scripts->add( 'wp-tinymce', includes_url( 'js/tinymce/' ) . "plugins/compat3x/plugin$dev_suffix.js", array( 'wp-tinymce-root' ), $tinymce_version );
    68         }
     73        // Load tinymce.js when running from /src, otherwise tinymce.min.js.
     74        $scripts->add( 'wp-tinymce-root', includes_url( 'js/tinymce/' ) . "tinymce$dev_suffix.js", array(), $tinymce_version );
     75        $scripts->add( 'wp-tinymce', includes_url( 'js/tinymce/' ) . "plugins/compat3x/plugin$dev_suffix.js", array( 'wp-tinymce-root' ), $tinymce_version );
    6976
    7077        $scripts->add( 'wp-tinymce-lists', includes_url( "js/tinymce/plugins/lists/plugin$suffix.js" ), array( 'wp-tinymce' ), $tinymce_version );
    … …  
    24992506 * Determines whether scripts and styles are concatenated on admin screens and the login screen.
    25002507 *
    2501  * Concatenation is on unless the `CONCATENATE_SCRIPTS` constant turns it off, and `SCRIPT_DEBUG`
     2508 * Concatenation is off unless the `CONCATENATE_SCRIPTS` constant turns it on, and `SCRIPT_DEBUG`
    25022509 * turns it off regardless. Scripts and styles are never concatenated elsewhere.
    25032510 *
    … …  
    25162523 */
    25172524function wp_should_concatenate_admin_scripts(): bool {
    2518         $concatenate = ( defined( 'CONCATENATE_SCRIPTS' ) ? (bool) CONCATENATE_SCRIPTS : true )
     2525        $concatenate = ( defined( 'CONCATENATE_SCRIPTS' ) ? (bool) CONCATENATE_SCRIPTS : false )
    25192526                && ! ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG );
    25202527
    … …  
    25332540         * @since 7.2.0
    25342541         *
    2535          * @param bool $concatenate Whether scripts and styles are concatenated. Default true, unless the
    2536          *                          `CONCATENATE_SCRIPTS` constant is false or `SCRIPT_DEBUG` is true.
     2542         * @param bool $concatenate Whether scripts and styles are concatenated. Default false, unless the
     2543         *                          `CONCATENATE_SCRIPTS` constant is true and `SCRIPT_DEBUG` is not.
    25372544         */
    25382545        return (bool) apply_filters( 'wp_should_concatenate_admin_scripts', $concatenate );
  • trunk/tests/phpunit/tests/dependencies/scripts.php

    r64120 r64320  
    3737
    3838        /**
     39         * @var mixed
     40         */
     41        protected $old_compress_scripts;
     42
     43        /**
    3944         * @var WP_Styles
    4045         */
    … …  
    5560                $this->old_wp_styles           = $GLOBALS['wp_styles'] ?? null;
    5661                $this->old_concatenate_scripts = $GLOBALS['concatenate_scripts'] ?? null;
     62                $this->old_compress_scripts    = $GLOBALS['compress_scripts'] ?? null;
    5763                remove_action( 'wp_default_scripts', 'wp_default_scripts' );
    5864                remove_action( 'wp_default_scripts', 'wp_default_packages' );
    … …  
    7884                $GLOBALS['wp_styles']           = $this->old_wp_styles;
    7985                $GLOBALS['concatenate_scripts'] = $this->old_concatenate_scripts;
     86                $GLOBALS['compress_scripts']    = $this->old_compress_scripts;
    8087                add_action( 'wp_default_scripts', 'wp_default_scripts' );
    8188                parent::tear_down();
    … …  
    38313838         */
    38323839        public function test_printing_tinymce_scripts() {
    3833                 global $wp_scripts;
    3834 
    3835                 wp_register_tinymce_scripts( $wp_scripts, true );
     3840                wp_register_tinymce_scripts( wp_scripts() );
    38363841
    38373842                $actual = get_echo( 'wp_print_scripts', array( array( 'wp-tinymce' ) ) );
    … …  
    38393844                $this->assertStringNotContainsString( 'async', $actual, 'TinyMCE should not have an async attribute.' );
    38403845                $this->assertStringNotContainsString( 'defer', $actual, 'TinyMCE should not have a defer attribute.' );
     3846        }
     3847
     3848        /**
     3849         * Tests that TinyMCE is registered as separate files, never as the `wp-tinymce.js` bundle.
     3850         *
     3851         * @ticket 57548
     3852         *
     3853         * @covers ::wp_register_tinymce_scripts
     3854         *
     3855         * @dataProvider data_register_tinymce_scripts_unbundled
     3856         *
     3857         * @param bool $concatenate Value of the `$concatenate_scripts` global.
     3858         * @param bool $compress    Value of the `$compress_scripts` global.
     3859         */
     3860        public function test_register_tinymce_scripts_unbundled( bool $concatenate, bool $compress ): void {
     3861                global $concatenate_scripts, $compress_scripts;
     3862
     3863                $concatenate_scripts = $concatenate;
     3864                $compress_scripts    = $compress;
     3865
     3866                $wp_scripts = wp_scripts();
     3867                wp_register_tinymce_scripts( $wp_scripts );
     3868
     3869                $root = $wp_scripts->query( 'wp-tinymce-root' );
     3870                $this->assertInstanceOf( _WP_Dependency::class, $root, 'Expected TinyMCE core to be registered.' );
     3871                $this->assertIsString( $root->src );
     3872                $this->assertMatchesRegularExpression( '#/js/tinymce/tinymce(\.min)?\.js$#', $root->src );
     3873
     3874                $tinymce = $wp_scripts->query( 'wp-tinymce' );
     3875                $this->assertInstanceOf( _WP_Dependency::class, $tinymce, 'Expected the wp-tinymce handle to be registered.' );
     3876                $this->assertIsString( $tinymce->src );
     3877                $this->assertMatchesRegularExpression( '#/js/tinymce/plugins/compat3x/plugin(\.min)?\.js$#', $tinymce->src );
     3878                $this->assertSame( array( 'wp-tinymce-root' ), $tinymce->deps );
     3879        }
     3880
     3881        /**
     3882         * Data provider for test_register_tinymce_scripts_unbundled().
     3883         *
     3884         * @return array<non-falsy-string, array{ concatenate: bool, compress: bool }>
     3885         */
     3886        public function data_register_tinymce_scripts_unbundled(): array {
     3887                return array(
     3888                        'concatenated and compressed' => array(
     3889                                'concatenate' => true,
     3890                                'compress'    => true,
     3891                        ),
     3892                        'concatenated only'           => array(
     3893                                'concatenate' => true,
     3894                                'compress'    => false,
     3895                        ),
     3896                        'compressed only'             => array(
     3897                                'concatenate' => false,
     3898                                'compress'    => true,
     3899                        ),
     3900                        'neither'                     => array(
     3901                                'concatenate' => false,
     3902                                'compress'    => false,
     3903                        ),
     3904                );
    38413905        }
    38423906
  • trunk/tests/phpunit/tests/dependencies/wpShouldConcatenateAdminScripts.php

    r64120 r64320  
    7575
    7676        /**
    77          * Tests the default when `CONCATENATE_SCRIPTS` is not defined, which is to concatenate unless
    78          * `SCRIPT_DEBUG` is on.
     77         * Tests the default when `CONCATENATE_SCRIPTS` is not defined, which is not to concatenate.
    7978         *
    8079         * @ticket 57548
    … …  
    8584                }
    8685
    87                 $this->assertSame( ! SCRIPT_DEBUG, wp_should_concatenate_admin_scripts() );
     86                $this->assertFalse( wp_should_concatenate_admin_scripts() );
    8887        }
    8988
    … …  
    9796                add_filter( 'wp_should_concatenate_admin_scripts', array( $filter, 'filter' ) );
    9897
    99                 $this->assertSame( ! SCRIPT_DEBUG && ( ! defined( 'CONCATENATE_SCRIPTS' ) || CONCATENATE_SCRIPTS ), wp_should_concatenate_admin_scripts() );
     98                $this->assertSame( ! SCRIPT_DEBUG && defined( 'CONCATENATE_SCRIPTS' ) && CONCATENATE_SCRIPTS, wp_should_concatenate_admin_scripts() );
    10099                $this->assertSame( 1, $filter->get_call_count() );
    101100
Note: See TracChangeset for help on using the changeset viewer.