mirror of
git://develop.git.wordpress.org/
synced 2025-05-13 23:35:27 +02:00
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. git-svn-id: https://develop.svn.wordpress.org/trunk@50836 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
2ac7f39570
commit
d5f900c3df
1
.gitignore
vendored
1
.gitignore
vendored
@ -28,6 +28,7 @@ wp-tests-config.php
|
||||
/src/wp-includes/css/dist
|
||||
/src/wp-includes/css/*.min.css
|
||||
/src/wp-includes/css/*-rtl.css
|
||||
/src/wp-includes/blocks/**/*.css
|
||||
/packagehash.txt
|
||||
|
||||
# Files and folders that get created in wp-content
|
||||
|
@ -157,24 +157,48 @@ function register_block_style_handle( $metadata, $field_name ) {
|
||||
if ( empty( $metadata[ $field_name ] ) ) {
|
||||
return false;
|
||||
}
|
||||
$is_core_block = isset( $metadata['file'] ) && 0 === strpos( $metadata['file'], ABSPATH . WPINC );
|
||||
if ( $is_core_block && ! should_load_separate_core_block_assets() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check whether styles should have a ".min" suffix or not.
|
||||
$suffix = SCRIPT_DEBUG ? '' : '.min';
|
||||
|
||||
$style_handle = $metadata[ $field_name ];
|
||||
$style_path = remove_block_asset_path_prefix( $metadata[ $field_name ] );
|
||||
if ( $style_handle === $style_path ) {
|
||||
|
||||
if ( $style_handle === $style_path && ! $is_core_block ) {
|
||||
return $style_handle;
|
||||
}
|
||||
|
||||
$style_uri = plugins_url( $style_path, $metadata['file'] );
|
||||
if ( $is_core_block ) {
|
||||
$style_path = "style$suffix.css";
|
||||
$style_uri = includes_url( 'blocks/' . str_replace( 'core/', '', $metadata['name'] ) . "/style$suffix.css" );
|
||||
}
|
||||
|
||||
$style_handle = generate_block_asset_handle( $metadata['name'], $field_name );
|
||||
$block_dir = dirname( $metadata['file'] );
|
||||
$style_file = realpath( "$block_dir/$style_path" );
|
||||
$version = file_exists( $style_file ) ? filemtime( $style_file ) : false;
|
||||
$result = wp_register_style(
|
||||
$style_handle,
|
||||
plugins_url( $style_path, $metadata['file'] ),
|
||||
$style_uri,
|
||||
array(),
|
||||
filemtime( $style_file )
|
||||
$version
|
||||
);
|
||||
if ( file_exists( str_replace( '.css', '-rtl.css', $style_file ) ) ) {
|
||||
wp_style_add_data( $style_handle, 'rtl', 'replace' );
|
||||
}
|
||||
if ( file_exists( $style_file ) ) {
|
||||
wp_style_add_data( $style_handle, 'path', $style_file );
|
||||
}
|
||||
|
||||
$rtl_file = str_replace( "$suffix.css", "-rtl$suffix.css", $style_file );
|
||||
if ( is_rtl() && file_exists( $rtl_file ) ) {
|
||||
wp_style_add_data( $style_handle, 'path', $rtl_file );
|
||||
}
|
||||
|
||||
return $result ? $style_handle : false;
|
||||
}
|
||||
@ -928,3 +952,26 @@ function block_has_support( $block_type, $feature, $default = false ) {
|
||||
|
||||
return true === $block_support || is_array( $block_support );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether separate assets should be loaded for core blocks.
|
||||
*
|
||||
* @since 5.8
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function should_load_separate_core_block_assets() {
|
||||
if ( is_admin() || is_feed() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Determine if separate styles & scripts will be loaded for blocks on-render or not.
|
||||
*
|
||||
* @since 5.8.0
|
||||
*
|
||||
* @param bool $load_separate_styles Whether separate styles will be loaded or not.
|
||||
*
|
||||
* @return bool Whether separate styles will be loaded or not.
|
||||
*/
|
||||
return apply_filters( 'separate_core_block_assets', false );
|
||||
}
|
||||
|
@ -551,6 +551,9 @@ add_filter( 'customize_controls_print_styles', 'wp_resource_hints', 1 );
|
||||
add_action( 'wp_default_styles', 'wp_default_styles' );
|
||||
add_filter( 'style_loader_src', 'wp_style_loader_src', 10, 2 );
|
||||
|
||||
add_action( 'wp_head', 'wp_maybe_inline_styles', 1 ); // Run for styles enqueued in <head>.
|
||||
add_action( 'wp_footer', 'wp_maybe_inline_styles', 1 ); // Run for late-loaded styles in the footer.
|
||||
|
||||
// Taxonomy.
|
||||
add_action( 'init', 'create_initial_taxonomies', 0 ); // Highest priority.
|
||||
add_action( 'change_locale', 'create_initial_taxonomies' );
|
||||
|
@ -1502,7 +1502,9 @@ function wp_default_styles( $styles ) {
|
||||
}
|
||||
$styles->add( 'wp-editor-font', $fonts_url ); // No longer used in core as of 5.7.
|
||||
|
||||
$styles->add( 'wp-block-library-theme', "/wp-includes/css/dist/block-library/theme$suffix.css" );
|
||||
$block_library_theme_path = "/wp-includes/css/dist/block-library/theme$suffix.css";
|
||||
$styles->add( 'wp-block-library-theme', $block_library_theme_path );
|
||||
$styles->add_data( 'wp-block-library-theme', 'path', ABSPATH . $block_library_theme_path );
|
||||
|
||||
$styles->add(
|
||||
'wp-reset-editor-styles',
|
||||
@ -1571,7 +1573,11 @@ function wp_default_styles( $styles ) {
|
||||
$handle = 'wp-' . $package;
|
||||
$path = "/wp-includes/css/dist/$package/style$suffix.css";
|
||||
|
||||
if ( 'block-library' === $package && should_load_separate_core_block_assets() ) {
|
||||
$path = "/wp-includes/css/dist/$package/common$suffix.css";
|
||||
}
|
||||
$styles->add( $handle, $path, $dependencies );
|
||||
$styles->add_data( $handle, 'path', ABSPATH . $path );
|
||||
}
|
||||
|
||||
// RTL CSS.
|
||||
@ -2277,6 +2283,10 @@ function wp_should_load_block_editor_scripts_and_styles() {
|
||||
function wp_enqueue_registered_block_scripts_and_styles() {
|
||||
global $current_screen;
|
||||
|
||||
if ( should_load_separate_core_block_assets() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$load_editor_scripts = is_admin() && wp_should_load_block_editor_scripts_and_styles();
|
||||
|
||||
$block_registry = WP_Block_Type_Registry::get_instance();
|
||||
@ -2495,3 +2505,80 @@ function wp_get_inline_script_tag( $javascript, $attributes = array() ) {
|
||||
function wp_print_inline_script_tag( $javascript, $attributes = array() ) {
|
||||
echo wp_get_inline_script_tag( $javascript, $attributes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow small styles to be inlined.
|
||||
* This improves performance and sustainability, and is opt-in.
|
||||
*
|
||||
* Stylesheets can opt-in by adding `path` data using `wp_style_add_data`, and defining the file's absolute path.
|
||||
* wp_style_add_data( $style_handle, 'path', $file_path );
|
||||
*
|
||||
* @since 5.8.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function wp_maybe_inline_styles() {
|
||||
|
||||
$total_inline_limit = 20000;
|
||||
/**
|
||||
* The maximum size of inlined styles in bytes.
|
||||
*
|
||||
* @param int $total_inline_limit The file-size threshold, in bytes. Defaults to 20000.
|
||||
* @return int The file-size threshold, in bytes.
|
||||
*/
|
||||
$total_inline_limit = apply_filters( 'styles_inline_size_limit', $total_inline_limit );
|
||||
|
||||
global $wp_styles;
|
||||
$styles = array();
|
||||
|
||||
// Build an array of styles that have a path defined.
|
||||
foreach ( $wp_styles->queue as $handle ) {
|
||||
if ( wp_styles()->get_data( $handle, 'path' ) && file_exists( $wp_styles->registered[ $handle ]->extra['path'] ) ) {
|
||||
$styles[] = array(
|
||||
'handle' => $handle,
|
||||
'path' => $wp_styles->registered[ $handle ]->extra['path'],
|
||||
'size' => filesize( $wp_styles->registered[ $handle ]->extra['path'] ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $styles ) ) {
|
||||
// Reorder styles array based on size.
|
||||
usort(
|
||||
$styles,
|
||||
function( $a, $b ) {
|
||||
return ( $a['size'] <= $b['size'] ) ? -1 : 1;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* The total inlined size.
|
||||
*
|
||||
* On each iteration of the loop, if a style gets added inline the value of this var increases
|
||||
* to reflect the total size of inlined styles.
|
||||
*/
|
||||
$total_inline_size = 0;
|
||||
|
||||
// Loop styles.
|
||||
foreach ( $styles as $style ) {
|
||||
|
||||
// Size check. Since styles are ordered by size, we can break the loop.
|
||||
if ( $total_inline_size + $style['size'] > $total_inline_limit ) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the styles if we don't already have them.
|
||||
$style['css'] = file_get_contents( $style['path'] );
|
||||
|
||||
// Set `src` to `false` and add styles inline.
|
||||
$wp_styles->registered[ $style['handle'] ]->src = false;
|
||||
if ( empty( $wp_styles->registered[ $style['handle'] ]->extra['after'] ) ) {
|
||||
$wp_styles->registered[ $style['handle'] ]->extra['after'] = array();
|
||||
}
|
||||
array_unshift( $wp_styles->registered[ $style['handle'] ]->extra['after'], $style['css'] );
|
||||
|
||||
// Add the styles size to the $total_inline_size var.
|
||||
$total_inline_size += (int) $style['size'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -270,6 +270,12 @@ class WP_Test_Block_Register extends WP_UnitTestCase {
|
||||
|
||||
$this->assertSame( 'unit-tests-test-block-style', $result );
|
||||
$this->assertSame( 'replace', wp_styles()->get_data( 'unit-tests-test-block-style', 'rtl' ) );
|
||||
|
||||
// @ticket 50328
|
||||
$this->assertSame(
|
||||
wp_normalize_path( realpath( DIR_TESTDATA . '/blocks/notice/block.css' ) ),
|
||||
wp_normalize_path( wp_styles()->get_data( 'unit-tests-test-block-style', 'path' ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -366,6 +372,12 @@ class WP_Test_Block_Register extends WP_UnitTestCase {
|
||||
$this->assertSame( 'tests-notice-script', $result->script );
|
||||
$this->assertSame( 'tests-notice-editor-style', $result->editor_style );
|
||||
$this->assertSame( 'tests-notice-style', $result->style );
|
||||
|
||||
// @ticket 50328
|
||||
$this->assertSame(
|
||||
wp_normalize_path( realpath( DIR_TESTDATA . '/blocks/notice/block.css' ) ),
|
||||
wp_normalize_path( wp_styles()->get_data( 'unit-tests-test-block-style', 'path' ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -420,4 +420,44 @@ CSS;
|
||||
wp_common_block_scripts_and_styles();
|
||||
$this->assertTrue( wp_style_is( 'wp-block-library-theme' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the main "style.css" file gets enqueued when the site doesn't opt-in to separate_core_block_assets.
|
||||
*
|
||||
* @ticket 50263
|
||||
*/
|
||||
function test_common_block_styles_for_viewing_without_split_styles() {
|
||||
add_filter( 'separate_core_block_assets', '__return_false' );
|
||||
wp_default_styles( $GLOBALS['wp_styles'] );
|
||||
|
||||
$this->assertSame(
|
||||
$GLOBALS['wp_styles']->registered['wp-block-library']->src,
|
||||
'/' . WPINC . '/css/dist/block-library/style.css'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the "common.css" file gets enqueued when the site opts-in to separate_core_block_assets.
|
||||
*
|
||||
* @ticket 50263
|
||||
*/
|
||||
function test_common_block_styles_for_viewing_with_split_styles() {
|
||||
add_filter( 'separate_core_block_assets', '__return_false' );
|
||||
wp_default_styles( $GLOBALS['wp_styles'] );
|
||||
|
||||
$this->assertSame(
|
||||
$GLOBALS['wp_styles']->registered['wp-block-library']->src,
|
||||
'/' . WPINC . '/css/dist/block-library/style.css'
|
||||
);
|
||||
}
|
||||
|
||||
function test_block_styles_for_viewing_with_split_styles() {
|
||||
add_filter( 'separate_core_block_assets', '__return_true' );
|
||||
wp_default_styles( $GLOBALS['wp_styles'] );
|
||||
|
||||
$this->assertSame(
|
||||
$GLOBALS['wp_styles']->registered['wp-block-library']->src,
|
||||
'/' . WPINC . '/css/dist/block-library/common.css'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -3788,6 +3788,164 @@ mockedApiResponse.Schema = {
|
||||
}
|
||||
]
|
||||
},
|
||||
"/wp/v2/blocks/(?P<parent>[\\d]+)/revisions": {
|
||||
"namespace": "wp/v2",
|
||||
"methods": [
|
||||
"GET"
|
||||
],
|
||||
"endpoints": [
|
||||
{
|
||||
"methods": [
|
||||
"GET"
|
||||
],
|
||||
"args": {
|
||||
"parent": {
|
||||
"description": "The ID for the parent of the object.",
|
||||
"type": "integer",
|
||||
"required": false
|
||||
},
|
||||
"context": {
|
||||
"description": "Scope under which the request is made; determines fields present in response.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"view",
|
||||
"embed",
|
||||
"edit"
|
||||
],
|
||||
"default": "view",
|
||||
"required": false
|
||||
},
|
||||
"page": {
|
||||
"description": "Current page of the collection.",
|
||||
"type": "integer",
|
||||
"default": 1,
|
||||
"minimum": 1,
|
||||
"required": false
|
||||
},
|
||||
"per_page": {
|
||||
"description": "Maximum number of items to be returned in result set.",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 100,
|
||||
"required": false
|
||||
},
|
||||
"search": {
|
||||
"description": "Limit results to those matching a string.",
|
||||
"type": "string",
|
||||
"required": false
|
||||
},
|
||||
"exclude": {
|
||||
"description": "Ensure result set excludes specific IDs.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
},
|
||||
"default": [],
|
||||
"required": false
|
||||
},
|
||||
"include": {
|
||||
"description": "Limit result set to specific IDs.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
},
|
||||
"default": [],
|
||||
"required": false
|
||||
},
|
||||
"offset": {
|
||||
"description": "Offset the result set by a specific number of items.",
|
||||
"type": "integer",
|
||||
"required": false
|
||||
},
|
||||
"order": {
|
||||
"description": "Order sort attribute ascending or descending.",
|
||||
"type": "string",
|
||||
"default": "desc",
|
||||
"enum": [
|
||||
"asc",
|
||||
"desc"
|
||||
],
|
||||
"required": false
|
||||
},
|
||||
"orderby": {
|
||||
"description": "Sort collection by object attribute.",
|
||||
"type": "string",
|
||||
"default": "date",
|
||||
"enum": [
|
||||
"date",
|
||||
"id",
|
||||
"include",
|
||||
"relevance",
|
||||
"slug",
|
||||
"include_slugs",
|
||||
"title"
|
||||
],
|
||||
"required": false
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"/wp/v2/blocks/(?P<parent>[\\d]+)/revisions/(?P<id>[\\d]+)": {
|
||||
"namespace": "wp/v2",
|
||||
"methods": [
|
||||
"GET",
|
||||
"DELETE"
|
||||
],
|
||||
"endpoints": [
|
||||
{
|
||||
"methods": [
|
||||
"GET"
|
||||
],
|
||||
"args": {
|
||||
"parent": {
|
||||
"description": "The ID for the parent of the object.",
|
||||
"type": "integer",
|
||||
"required": false
|
||||
},
|
||||
"id": {
|
||||
"description": "Unique identifier for the object.",
|
||||
"type": "integer",
|
||||
"required": false
|
||||
},
|
||||
"context": {
|
||||
"description": "Scope under which the request is made; determines fields present in response.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"view",
|
||||
"embed",
|
||||
"edit"
|
||||
],
|
||||
"default": "view",
|
||||
"required": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"methods": [
|
||||
"DELETE"
|
||||
],
|
||||
"args": {
|
||||
"parent": {
|
||||
"description": "The ID for the parent of the object.",
|
||||
"type": "integer",
|
||||
"required": false
|
||||
},
|
||||
"id": {
|
||||
"description": "Unique identifier for the object.",
|
||||
"type": "integer",
|
||||
"required": false
|
||||
},
|
||||
"force": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Required to be true, as revisions do not support trashing.",
|
||||
"required": false
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"/wp/v2/blocks/(?P<id>[\\d]+)/autosaves": {
|
||||
"namespace": "wp/v2",
|
||||
"methods": [
|
||||
|
@ -214,6 +214,32 @@ module.exports = function( env = { environment: 'production', watch: false, buil
|
||||
to: join( baseDir, `src/${ blockMetadataFiles[ filename ] }` ),
|
||||
} ) );
|
||||
|
||||
const blockStylesheetCopies = blockFolders.map( ( blockName ) => ( {
|
||||
from: join( baseDir, `node_modules/@wordpress/block-library/build-style/${ blockName }/*.css` ),
|
||||
to: join( baseDir, `${ buildTarget }/blocks/${ blockName }/` ),
|
||||
flatten: true,
|
||||
transform: ( content ) => {
|
||||
if ( mode === 'production' ) {
|
||||
return postcss( [
|
||||
require( 'cssnano' )( {
|
||||
preset: 'default',
|
||||
} ),
|
||||
] )
|
||||
.process( content, { from: 'src/app.css', to: 'dest/app.css' } )
|
||||
.then( ( result ) => result.css );
|
||||
}
|
||||
|
||||
return content;
|
||||
},
|
||||
transformPath: ( targetPath, sourcePath ) => {
|
||||
if ( mode === 'production' ) {
|
||||
return targetPath.replace( /\.css$/, '.min.css' );
|
||||
}
|
||||
|
||||
return targetPath;
|
||||
}
|
||||
} ) );
|
||||
|
||||
const config = {
|
||||
mode,
|
||||
|
||||
@ -302,6 +328,7 @@ module.exports = function( env = { environment: 'production', watch: false, buil
|
||||
...cssCopies,
|
||||
...phpCopies,
|
||||
...blockMetadataCopies,
|
||||
...blockStylesheetCopies,
|
||||
],
|
||||
),
|
||||
],
|
||||
|
Loading…
x
Reference in New Issue
Block a user