Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow loading block-styles on render (opt-in) + inlining #1236

Closed
wants to merge 35 commits into from
Closed
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
cafd211
add separate styles per block
aristath May 6, 2021
12e37f3
move styles to the block.json folders
aristath May 6, 2021
ae23c66
Tweak to accommodate core styles
aristath May 6, 2021
9f8883a
Still a WIP, but as a POC it works
aristath May 6, 2021
5c83e24
Add 'path' to core styles & only load if filter is true
aristath May 7, 2021
1abaab7
use min files if needed
aristath May 7, 2021
44c2cc5
check if admin/rest request
aristath May 7, 2021
e9c2cdd
Change the main stylesheet if we need to load separate assets
aristath May 7, 2021
78da83b
inline docs & syntax tweaks
aristath May 7, 2021
96f9216
backport inlining methods
aristath May 7, 2021
ce1a2bf
Add path data to core stylesheets for blocks
aristath May 7, 2021
c1edd86
fix version & file-exist checks
aristath May 7, 2021
02e2f1e
Make sure "name" is set before using it.
aristath May 7, 2021
a901d99
Add tests
aristath May 7, 2021
c852626
bad test
aristath May 7, 2021
2b70c49
another fix & 2 more tests
aristath May 7, 2021
2d66fb0
test
aristath May 7, 2021
0b64780
CS: missing comma
aristath May 7, 2021
539723f
WIP fix
aristath May 7, 2021
06ab2f2
typo
aristath May 7, 2021
9f325b9
bad test
aristath May 7, 2021
b48c9aa
copy/paste error in test, they were both the same
aristath May 7, 2021
51916ea
restore hook and move condition in the function
aristath May 7, 2021
9b8831c
improve copy script in webpack
aristath May 7, 2021
eda6ca7
inline docs for the filter
aristath May 7, 2021
157f4f6
Merge branch 'master' into fix/50328
aristath May 10, 2021
6c62c73
Detect if core block based on path
aristath May 10, 2021
b9139c2
test simplification
aristath May 10, 2021
82cbe21
rtl fix
aristath May 10, 2021
29d6f85
rename function
aristath May 10, 2021
a5f86ad
Update src/wp-includes/blocks.php
aristath May 10, 2021
e97f747
update filter name
aristath May 10, 2021
288c2d3
move return condition to the top, props @gziolo
aristath May 10, 2021
cdb3218
Ignore compiled CSS files
aristath May 10, 2021
ab1b95f
Add missing slash
aristath May 11, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 53 additions & 3 deletions src/wp-includes/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,24 +157,51 @@ function register_block_style_handle( $metadata, $field_name ) {
if ( empty( $metadata[ $field_name ] ) ) {
return false;
}

// Check whether styles should have a ".min" suffix or not.
$suffix = SCRIPT_DEBUG ? '' : '.min';

$is_core_block = isset( $metadata['file'] ) && 0 === strpos( $metadata['file'], ABSPATH . WPINC );
$should_register = ! $is_core_block || should_load_separate_block_assets();

$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;
}

if ( ! $should_register ) {
aristath marked this conversation as resolved.
Show resolved Hide resolved
return false;
}

$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;
}
Expand Down Expand Up @@ -928,3 +955,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_block_assets() {
aristath marked this conversation as resolved.
Show resolved Hide resolved
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.
*
aristath marked this conversation as resolved.
Show resolved Hide resolved
* @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( 'load_separate_block_assets', false );
aristath marked this conversation as resolved.
Show resolved Hide resolved
}
5 changes: 4 additions & 1 deletion src/wp-includes/default-filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -537,8 +537,8 @@
add_action( 'wp_enqueue_scripts', 'wp_common_block_scripts_and_styles' );
add_action( 'admin_enqueue_scripts', 'wp_localize_jquery_ui_datepicker', 1000 );
add_action( 'admin_enqueue_scripts', 'wp_common_block_scripts_and_styles' );
add_action( 'enqueue_block_assets', 'wp_enqueue_registered_block_scripts_and_styles' );
aristath marked this conversation as resolved.
Show resolved Hide resolved
add_action( 'enqueue_block_assets', 'enqueue_block_styles_assets', 30 );
add_action( 'enqueue_block_assets', 'wp_enqueue_registered_block_scripts_and_styles' );
add_action( 'enqueue_block_editor_assets', 'wp_enqueue_registered_block_scripts_and_styles' );
add_action( 'enqueue_block_editor_assets', 'enqueue_editor_block_styles_assets' );
add_action( 'enqueue_block_editor_assets', 'wp_enqueue_editor_block_directory_assets' );
Expand All @@ -551,6 +551,9 @@
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' );
Expand Down
89 changes: 88 additions & 1 deletion src/wp-includes/script-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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_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.
Expand Down Expand Up @@ -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_block_assets() ) {
return;
}

$load_editor_scripts = is_admin() && wp_should_load_block_editor_scripts_and_styles();

$block_registry = WP_Block_Type_Registry::get_instance();
Expand Down Expand Up @@ -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'];
}
}
}
12 changes: 12 additions & 0 deletions tests/phpunit/tests/blocks/register.php
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,12 @@ function test_success_register_block_style_handle() {

$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' ) )
);
}

/**
Expand Down Expand Up @@ -366,6 +372,12 @@ function test_block_registers_with_metadata_fixture() {
$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' ) )
);
}

/**
Expand Down
40 changes: 40 additions & 0 deletions tests/phpunit/tests/dependencies/styles.php
Original file line number Diff line number Diff line change
Expand Up @@ -420,4 +420,44 @@ function test_block_styles_for_viewing_with_theme_support() {
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 load_separate_block_assets.
*
* @ticket 50263
*/
function test_common_block_styles_for_viewing_without_split_styles() {
add_filter( 'load_separate_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 load_separate_block_assets.
*
* @ticket 50263
*/
function test_common_block_styles_for_viewing_with_split_styles() {
add_filter( 'load_separate_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( 'load_separate_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'
);
}
}
27 changes: 27 additions & 0 deletions tools/webpack/packages.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,32 @@ module.exports = function( env = { environment: 'production', watch: false, buil
to: join( baseDir, `src/${ blockMetadataFiles[ filename ] }` ),
} ) );

const blockStylesheetCopies = blockFolders.map( ( blockName ) => ( {
aristath marked this conversation as resolved.
Show resolved Hide resolved
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,

Expand Down Expand Up @@ -302,6 +328,7 @@ module.exports = function( env = { environment: 'production', watch: false, buil
...cssCopies,
...phpCopies,
...blockMetadataCopies,
...blockStylesheetCopies,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This adds 260 CSS files to subfolders in src/wp-includes/blocks. It won't scale well because they can change not only when the content of files updates but also when we modify webpack configuration. In this folder, we also have block.json files and PHP files copied over from WordPress packages with webpack. The only file that is custom is inside index.php. Ideally, we should remove all files inside src/wp-include/blocks from tracking in svn and leave it to the build process. I think it was proposed by @peterwilsoncc in https://core.trac.wordpress.org/ticket/49635.

],
),
],
Expand Down