WordPress.org

Make WordPress Core

Changeset 50836


Ignore:
Timestamp:
05/11/2021 09:41:48 AM (4 months 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.