Make WordPress Core

Changeset 50836


Ignore:
Timestamp:
05/11/2021 09:41:48 AM (5 years ago)
Author:
gziolo
Message:

Editor: Enqueue script and style assets only for blocks present on the page

Adds styles for individual core blocks to make it possible to render only styles for those blocks that are rendered on the page (frontend). This is optinal functionality for start that can be controlled with the new separate_core_block_assets filter.

In addition to that, styles can be inlined when path is passed when registering an individual styles. This functionality can be changed with the new styles_inline_size_limit filter. The maximum size of inlined styles in bytes defaults to 20 000.

Props aristath, aduth, westonruter, mcsf.
Fixes #50328, #52620.

Location:
trunk
Files:
51 edited

Legend:

Unmodified
Added
Removed
  • trunk/.gitignore

    r50349 r50836  
    2929/src/wp-includes/css/*.min.css
    3030/src/wp-includes/css/*-rtl.css
     31/src/wp-includes/blocks/**/*.css
    3132/packagehash.txt
    3233
  • trunk/src/wp-includes/blocks

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks.php

    r50761 r50836  
    158158                return false;
    159159        }
     160        $is_core_block = isset( $metadata['file'] ) && 0 === strpos( $metadata['file'], ABSPATH . WPINC );
     161        if ( $is_core_block && ! should_load_separate_core_block_assets() ) {
     162                return false;
     163        }
     164
     165        // Check whether styles should have a ".min" suffix or not.
     166        $suffix = SCRIPT_DEBUG ? '' : '.min';
     167
    160168        $style_handle = $metadata[ $field_name ];
    161169        $style_path   = remove_block_asset_path_prefix( $metadata[ $field_name ] );
    162         if ( $style_handle === $style_path ) {
     170
     171        if ( $style_handle === $style_path && ! $is_core_block ) {
    163172                return $style_handle;
     173        }
     174
     175        $style_uri = plugins_url( $style_path, $metadata['file'] );
     176        if ( $is_core_block ) {
     177                $style_path = "style$suffix.css";
     178                $style_uri  = includes_url( 'blocks/' . str_replace( 'core/', '', $metadata['name'] ) . "/style$suffix.css" );
    164179        }
    165180
     
    167182        $block_dir    = dirname( $metadata['file'] );
    168183        $style_file   = realpath( "$block_dir/$style_path" );
     184        $version      = file_exists( $style_file ) ? filemtime( $style_file ) : false;
    169185        $result       = wp_register_style(
    170186                $style_handle,
    171                 plugins_url( $style_path, $metadata['file'] ),
     187                $style_uri,
    172188                array(),
    173                 filemtime( $style_file )
     189                $version
    174190        );
    175191        if ( file_exists( str_replace( '.css', '-rtl.css', $style_file ) ) ) {
    176192                wp_style_add_data( $style_handle, 'rtl', 'replace' );
     193        }
     194        if ( file_exists( $style_file ) ) {
     195                wp_style_add_data( $style_handle, 'path', $style_file );
     196        }
     197
     198        $rtl_file = str_replace( "$suffix.css", "-rtl$suffix.css", $style_file );
     199        if ( is_rtl() && file_exists( $rtl_file ) ) {
     200                wp_style_add_data( $style_handle, 'path', $rtl_file );
    177201        }
    178202
     
    929953        return true === $block_support || is_array( $block_support );
    930954}
     955
     956/**
     957 * Checks whether separate assets should be loaded for core blocks.
     958 *
     959 * @since 5.8
     960 *
     961 * @return bool
     962 */
     963function should_load_separate_core_block_assets() {
     964        if ( is_admin() || is_feed() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
     965                return false;
     966        }
     967        /**
     968         * Determine if separate styles & scripts will be loaded for blocks on-render or not.
     969         *
     970         * @since 5.8.0
     971         *
     972         * @param bool $load_separate_styles Whether separate styles will be loaded or not.
     973         *
     974         * @return bool Whether separate styles will be loaded or not.
     975         */
     976        return apply_filters( 'separate_core_block_assets', false );
     977}
  • trunk/src/wp-includes/blocks/archives

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/audio

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/block

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/button

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/buttons

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/calendar

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/categories

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/code

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/column

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/columns

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/cover

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/embed

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/file

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/freeform

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/gallery

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/group

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/heading

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/html

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/image

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/latest-comments

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/latest-posts

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/list

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/media-text

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/missing

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/more

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/nextpage

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/paragraph

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/preformatted

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/pullquote

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/quote

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/rss

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/search

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/separator

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/shortcode

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/social-link

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/social-links

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/spacer

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/table

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/tag-cloud

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/text-columns

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/verse

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/blocks/video

    • Property svn:ignore set to
      *.css
  • trunk/src/wp-includes/default-filters.php

    r50629 r50836  
    552552add_filter( 'style_loader_src', 'wp_style_loader_src', 10, 2 );
    553553
     554add_action( 'wp_head', 'wp_maybe_inline_styles', 1 ); // Run for styles enqueued in <head>.
     555add_action( 'wp_footer', 'wp_maybe_inline_styles', 1 ); // Run for late-loaded styles in the footer.
     556
    554557// Taxonomy.
    555558add_action( 'init', 'create_initial_taxonomies', 0 ); // Highest priority.
  • trunk/src/wp-includes/script-loader.php

    r50773 r50836  
    15031503        $styles->add( 'wp-editor-font', $fonts_url ); // No longer used in core as of 5.7.
    15041504
    1505         $styles->add( 'wp-block-library-theme', "/wp-includes/css/dist/block-library/theme$suffix.css" );
     1505        $block_library_theme_path = "/wp-includes/css/dist/block-library/theme$suffix.css";
     1506        $styles->add( 'wp-block-library-theme', $block_library_theme_path );
     1507        $styles->add_data( 'wp-block-library-theme', 'path', ABSPATH . $block_library_theme_path );
    15061508
    15071509        $styles->add(
     
    15721574                $path   = "/wp-includes/css/dist/$package/style$suffix.css";
    15731575
     1576                if ( 'block-library' === $package && should_load_separate_core_block_assets() ) {
     1577                        $path = "/wp-includes/css/dist/$package/common$suffix.css";
     1578                }
    15741579                $styles->add( $handle, $path, $dependencies );
     1580                $styles->add_data( $handle, 'path', ABSPATH . $path );
    15751581        }
    15761582
     
    22782284        global $current_screen;
    22792285
     2286        if ( should_load_separate_core_block_assets() ) {
     2287                return;
     2288        }
     2289
    22802290        $load_editor_scripts = is_admin() && wp_should_load_block_editor_scripts_and_styles();
    22812291
     
    24962506        echo wp_get_inline_script_tag( $javascript, $attributes );
    24972507}
     2508
     2509/**
     2510 * Allow small styles to be inlined.
     2511 * This improves performance and sustainability, and is opt-in.
     2512 *
     2513 * Stylesheets can opt-in by adding `path` data using `wp_style_add_data`, and defining the file's absolute path.
     2514 * wp_style_add_data( $style_handle, 'path', $file_path );
     2515 *
     2516 * @since 5.8.0
     2517 *
     2518 * @return void
     2519 */
     2520function wp_maybe_inline_styles() {
     2521
     2522        $total_inline_limit = 20000;
     2523        /**
     2524         * The maximum size of inlined styles in bytes.
     2525         *
     2526         * @param int $total_inline_limit The file-size threshold, in bytes. Defaults to 20000.
     2527         * @return int                    The file-size threshold, in bytes.
     2528         */
     2529        $total_inline_limit = apply_filters( 'styles_inline_size_limit', $total_inline_limit );
     2530
     2531        global $wp_styles;
     2532        $styles = array();
     2533
     2534        // Build an array of styles that have a path defined.
     2535        foreach ( $wp_styles->queue as $handle ) {
     2536                if ( wp_styles()->get_data( $handle, 'path' ) && file_exists( $wp_styles->registered[ $handle ]->extra['path'] ) ) {
     2537                        $styles[] = array(
     2538                                'handle' => $handle,
     2539                                'path'   => $wp_styles->registered[ $handle ]->extra['path'],
     2540                                'size'   => filesize( $wp_styles->registered[ $handle ]->extra['path'] ),
     2541                        );
     2542                }
     2543        }
     2544
     2545        if ( ! empty( $styles ) ) {
     2546                // Reorder styles array based on size.
     2547                usort(
     2548                        $styles,
     2549                        function( $a, $b ) {
     2550                                return ( $a['size'] <= $b['size'] ) ? -1 : 1;
     2551                        }
     2552                );
     2553
     2554                /**
     2555                 * The total inlined size.
     2556                 *
     2557                 * On each iteration of the loop, if a style gets added inline the value of this var increases
     2558                 * to reflect the total size of inlined styles.
     2559                 */
     2560                $total_inline_size = 0;
     2561
     2562                // Loop styles.
     2563                foreach ( $styles as $style ) {
     2564
     2565                        // Size check. Since styles are ordered by size, we can break the loop.
     2566                        if ( $total_inline_size + $style['size'] > $total_inline_limit ) {
     2567                                break;
     2568                        }
     2569
     2570                        // Get the styles if we don't already have them.
     2571                        $style['css'] = file_get_contents( $style['path'] );
     2572
     2573                        // Set `src` to `false` and add styles inline.
     2574                        $wp_styles->registered[ $style['handle'] ]->src = false;
     2575                        if ( empty( $wp_styles->registered[ $style['handle'] ]->extra['after'] ) ) {
     2576                                $wp_styles->registered[ $style['handle'] ]->extra['after'] = array();
     2577                        }
     2578                        array_unshift( $wp_styles->registered[ $style['handle'] ]->extra['after'], $style['css'] );
     2579
     2580                        // Add the styles size to the $total_inline_size var.
     2581                        $total_inline_size += (int) $style['size'];
     2582                }
     2583        }
     2584}
  • trunk/tests/phpunit/tests/blocks/register.php

    r50450 r50836  
    271271                $this->assertSame( 'unit-tests-test-block-style', $result );
    272272                $this->assertSame( 'replace', wp_styles()->get_data( 'unit-tests-test-block-style', 'rtl' ) );
     273
     274                // @ticket 50328
     275                $this->assertSame(
     276                        wp_normalize_path( realpath( DIR_TESTDATA . '/blocks/notice/block.css' ) ),
     277                        wp_normalize_path( wp_styles()->get_data( 'unit-tests-test-block-style', 'path' ) )
     278                );
    273279        }
    274280
     
    367373                $this->assertSame( 'tests-notice-editor-style', $result->editor_style );
    368374                $this->assertSame( 'tests-notice-style', $result->style );
     375
     376                // @ticket 50328
     377                $this->assertSame(
     378                        wp_normalize_path( realpath( DIR_TESTDATA . '/blocks/notice/block.css' ) ),
     379                        wp_normalize_path( wp_styles()->get_data( 'unit-tests-test-block-style', 'path' ) )
     380                );
    369381        }
    370382
  • trunk/tests/phpunit/tests/dependencies/styles.php

    r50287 r50836  
    421421                $this->assertTrue( wp_style_is( 'wp-block-library-theme' ) );
    422422        }
     423
     424        /**
     425         * Tests that the main "style.css" file gets enqueued when the site doesn't opt-in to separate_core_block_assets.
     426         *
     427         * @ticket 50263
     428         */
     429        function test_common_block_styles_for_viewing_without_split_styles() {
     430                add_filter( 'separate_core_block_assets', '__return_false' );
     431                wp_default_styles( $GLOBALS['wp_styles'] );
     432
     433                $this->assertSame(
     434                        $GLOBALS['wp_styles']->registered['wp-block-library']->src,
     435                        '/' . WPINC . '/css/dist/block-library/style.css'
     436                );
     437        }
     438
     439        /**
     440         * Tests that the "common.css" file gets enqueued when the site opts-in to separate_core_block_assets.
     441         *
     442         * @ticket 50263
     443         */
     444        function test_common_block_styles_for_viewing_with_split_styles() {
     445                add_filter( 'separate_core_block_assets', '__return_false' );
     446                wp_default_styles( $GLOBALS['wp_styles'] );
     447
     448                $this->assertSame(
     449                        $GLOBALS['wp_styles']->registered['wp-block-library']->src,
     450                        '/' . WPINC . '/css/dist/block-library/style.css'
     451                );
     452        }
     453
     454        function test_block_styles_for_viewing_with_split_styles() {
     455                add_filter( 'separate_core_block_assets', '__return_true' );
     456                wp_default_styles( $GLOBALS['wp_styles'] );
     457
     458                $this->assertSame(
     459                        $GLOBALS['wp_styles']->registered['wp-block-library']->src,
     460                        '/' . WPINC . '/css/dist/block-library/common.css'
     461                );
     462        }
    423463}
  • trunk/tests/qunit/fixtures/wp-api-generated.js

    r50761 r50836  
    37893789            ]
    37903790        },
     3791        "/wp/v2/blocks/(?P<parent>[\\d]+)/revisions": {
     3792            "namespace": "wp/v2",
     3793            "methods": [
     3794                "GET"
     3795            ],
     3796            "endpoints": [
     3797                {
     3798                    "methods": [
     3799                        "GET"
     3800                    ],
     3801                    "args": {
     3802                        "parent": {
     3803                            "description": "The ID for the parent of the object.",
     3804                            "type": "integer",
     3805                            "required": false
     3806                        },
     3807                        "context": {
     3808                            "description": "Scope under which the request is made; determines fields present in response.",
     3809                            "type": "string",
     3810                            "enum": [
     3811                                "view",
     3812                                "embed",
     3813                                "edit"
     3814                            ],
     3815                            "default": "view",
     3816                            "required": false
     3817                        },
     3818                        "page": {
     3819                            "description": "Current page of the collection.",
     3820                            "type": "integer",
     3821                            "default": 1,
     3822                            "minimum": 1,
     3823                            "required": false
     3824                        },
     3825                        "per_page": {
     3826                            "description": "Maximum number of items to be returned in result set.",
     3827                            "type": "integer",
     3828                            "minimum": 1,
     3829                            "maximum": 100,
     3830                            "required": false
     3831                        },
     3832                        "search": {
     3833                            "description": "Limit results to those matching a string.",
     3834                            "type": "string",
     3835                            "required": false
     3836                        },
     3837                        "exclude": {
     3838                            "description": "Ensure result set excludes specific IDs.",
     3839                            "type": "array",
     3840                            "items": {
     3841                                "type": "integer"
     3842                            },
     3843                            "default": [],
     3844                            "required": false
     3845                        },
     3846                        "include": {
     3847                            "description": "Limit result set to specific IDs.",
     3848                            "type": "array",
     3849                            "items": {
     3850                                "type": "integer"
     3851                            },
     3852                            "default": [],
     3853                            "required": false
     3854                        },
     3855                        "offset": {
     3856                            "description": "Offset the result set by a specific number of items.",
     3857                            "type": "integer",
     3858                            "required": false
     3859                        },
     3860                        "order": {
     3861                            "description": "Order sort attribute ascending or descending.",
     3862                            "type": "string",
     3863                            "default": "desc",
     3864                            "enum": [
     3865                                "asc",
     3866                                "desc"
     3867                            ],
     3868                            "required": false
     3869                        },
     3870                        "orderby": {
     3871                            "description": "Sort collection by object attribute.",
     3872                            "type": "string",
     3873                            "default": "date",
     3874                            "enum": [
     3875                                "date",
     3876                                "id",
     3877                                "include",
     3878                                "relevance",
     3879                                "slug",
     3880                                "include_slugs",
     3881                                "title"
     3882                            ],
     3883                            "required": false
     3884                        }
     3885                    }
     3886                }
     3887            ]
     3888        },
     3889        "/wp/v2/blocks/(?P<parent>[\\d]+)/revisions/(?P<id>[\\d]+)": {
     3890            "namespace": "wp/v2",
     3891            "methods": [
     3892                "GET",
     3893                "DELETE"
     3894            ],
     3895            "endpoints": [
     3896                {
     3897                    "methods": [
     3898                        "GET"
     3899                    ],
     3900                    "args": {
     3901                        "parent": {
     3902                            "description": "The ID for the parent of the object.",
     3903                            "type": "integer",
     3904                            "required": false
     3905                        },
     3906                        "id": {
     3907                            "description": "Unique identifier for the object.",
     3908                            "type": "integer",
     3909                            "required": false
     3910                        },
     3911                        "context": {
     3912                            "description": "Scope under which the request is made; determines fields present in response.",
     3913                            "type": "string",
     3914                            "enum": [
     3915                                "view",
     3916                                "embed",
     3917                                "edit"
     3918                            ],
     3919                            "default": "view",
     3920                            "required": false
     3921                        }
     3922                    }
     3923                },
     3924                {
     3925                    "methods": [
     3926                        "DELETE"
     3927                    ],
     3928                    "args": {
     3929                        "parent": {
     3930                            "description": "The ID for the parent of the object.",
     3931                            "type": "integer",
     3932                            "required": false
     3933                        },
     3934                        "id": {
     3935                            "description": "Unique identifier for the object.",
     3936                            "type": "integer",
     3937                            "required": false
     3938                        },
     3939                        "force": {
     3940                            "type": "boolean",
     3941                            "default": false,
     3942                            "description": "Required to be true, as revisions do not support trashing.",
     3943                            "required": false
     3944                        }
     3945                    }
     3946                }
     3947            ]
     3948        },
    37913949        "/wp/v2/blocks/(?P<id>[\\d]+)/autosaves": {
    37923950            "namespace": "wp/v2",
  • trunk/tools/webpack/packages.js

    r50824 r50836  
    215215        } ) );
    216216
     217        const blockStylesheetCopies = blockFolders.map( ( blockName ) => ( {
     218                from: join( baseDir, `node_modules/@wordpress/block-library/build-style/${ blockName }/*.css` ),
     219                to: join( baseDir, `${ buildTarget }/blocks/${ blockName }/` ),
     220                flatten: true,
     221                transform: ( content ) => {
     222                        if ( mode === 'production' ) {
     223                                return postcss( [
     224                                        require( 'cssnano' )( {
     225                                                preset: 'default',
     226                                        } ),
     227                                ] )
     228                                        .process( content, { from: 'src/app.css', to: 'dest/app.css' } )
     229                                        .then( ( result ) => result.css );
     230                        }
     231
     232                        return content;
     233                },
     234                transformPath: ( targetPath, sourcePath ) => {
     235                        if ( mode === 'production' ) {
     236                                return targetPath.replace( /\.css$/, '.min.css' );
     237                        }
     238
     239                        return targetPath;
     240                }
     241        } ) );
     242
    217243        const config = {
    218244                mode,
     
    303329                                        ...phpCopies,
    304330                                        ...blockMetadataCopies,
     331                                        ...blockStylesheetCopies,
    305332                                ],
    306333                        ),
Note: See TracChangeset for help on using the changeset viewer.