Skip to content

Commit

Permalink
Improve loading method for block styles (#28358)
Browse files Browse the repository at this point in the history
* Inline styles if size is smaller than a threshold

* Add a global pool to avoid too many inline styles

* change default max pool size to 20k

* Add the original block-name as a param in filters

* Refactor the should-inline calculations

* Use a transient to cache file sizes

* Cleanup

* make sure size is an integer

* Change threshold to 1500

* Remove the total size checks

* Completely refactor the implementation

* Break the loop when appropriate

* changed limit to 20k

* simplify

* more tweaks

* Use wp_style_add_data, props @gziolo

* Simplify condition - props @gziolo

* Add file_exists check back

* simplify sorting function

* rename var from $stylesheet to $style

* typecasting not needed here

* rename functions

* Add basic phpunit tests for the minify function

* Allow inlining the common.css file if possible

* improve inline doc

* inline docs tweak

* Add wp_style_add_data in docs example

* docs
  • Loading branch information
aristath authored Feb 22, 2021
1 parent 9f7559e commit 0e90abf
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ function gutenberg_examples_02_register_block() {
filemtime( plugin_dir_path( __FILE__ ) . 'style.css' )
);

// Allow inlining small stylesheets on the frontend if possible.
wp_style_add_data( 'gutenberg-examples-02', 'path', dirname( __FILE__ ) . '/style.css' );

register_block_type( 'gutenberg-examples/example-02-stylesheets', array(
'apiVersion' => 2,
'style' => 'gutenberg-examples-02',
Expand Down
102 changes: 102 additions & 0 deletions lib/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ function gutenberg_register_core_block_styles( $block_name ) {
filemtime( gutenberg_dir_path() . $style_path )
);
wp_style_add_data( "wp-block-{$block_name}", 'rtl', 'replace' );

// Add a reference to the stylesheet's path to allow calculations for inlining styles in `wp_head`.
wp_style_add_data( "wp-block-{$block_name}", 'path', gutenberg_dir_path() . $style_path );
}

if ( file_exists( gutenberg_dir_path() . $editor_style_path ) ) {
Expand All @@ -193,6 +196,105 @@ function gutenberg_register_core_block_styles( $block_name ) {
}
}

/**
* Change the way styles get loaded depending on their size.
*
* Optimizes performance and sustainability of styles by inlining smaller stylesheets.
*
* @return void
*/
function gutenberg_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'] ) ) {
$block_styles = false;
$styles_size = filesize( $wp_styles->registered[ $handle ]->extra['path'] );

// Minify styles and get their minified size if SCRIPT_DEBUG is not enabled.
if ( ! defined( 'SCRIPT_DEBUG' ) || ! SCRIPT_DEBUG ) {
// Get the styles and minify them by removing comments & whitespace.
$block_styles = gutenberg_get_minified_styles( file_get_contents( $wp_styles->registered[ $handle ]->extra['path'] ) );
// Get the styles size.
$styles_size = strlen( $block_styles );
}

$styles[] = array(
'handle' => $handle,
'path' => $wp_styles->registered[ $handle ]->extra['path'],
'size' => $styles_size,
'css' => $block_styles,
);
}
}

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'] = $style['css'] ? $style['css'] : file_get_contents( $style['path'] );

// Set `src` to `false` and add styles inline.
$wp_styles->registered[ $style['handle'] ]->src = false;
$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'];
}
}
}
add_action( 'wp_head', 'gutenberg_maybe_inline_styles', 1 );

/**
* Minify styles.
*
* Removes inline comments and whitespace.
*
* @param string $styles The styles to be minified.
* @return string
*/
function gutenberg_get_minified_styles( $styles ) {
$re1 = '(?sx)("(?:[^"\\\\]++|\\\\.)*+"|\'(?:[^\'\\\\]++|\\\\.)*+\')|/\\* (?> .*? \\*/ )';
$re2 = '(?six)("(?:[^"\\\\]++|\\\\.)*+"|\'(?:[^\'\\\\]++|\\\\.)*+\')|\\s*+ ; \\s*+ ( } ) \\s*+|\\s*+ ( [*$~^|]?+= | [{};,>~+-] | !important\\b ) \\s*+|( [[(:] ) \\s++|\\s++ ( [])] )|\\s++ ( : ) \\s*+(?!(?>[^{}"\']++|"(?:[^"\\\\]++|\\\\.)*+"|\'(?:[^\'\\\\]++|\\\\.)*+\')*+{)|^ \\s++ | \\s++ \\z|(\\s)\\s+';

$styles = preg_replace( "%$re1%", '$1', $styles );
return preg_replace( "%$re2%", '$1$2$3$4$5$6$7', $styles );
}

/**
* Complements the implementation of block type `core/social-icon`, whether it
* be provided by core or the plugin, with derived block types for each
Expand Down
1 change: 1 addition & 0 deletions lib/client-assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ function gutenberg_register_packages_styles( $styles ) {
filemtime( gutenberg_dir_path() . 'build/block-library/' . $block_library_filename . '.css' )
);
$styles->add_data( 'wp-block-library', 'rtl', 'replace' );
$styles->add_data( 'wp-block-library', 'path', gutenberg_dir_path() . 'build/block-library/' . $block_library_filename . '.css' );

gutenberg_override_style(
$styles,
Expand Down
31 changes: 31 additions & 0 deletions phpunit/class-gutenberg-utils-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,35 @@ public function test_invalid_parameters_set() {
array( 'a' => 2 )
);
}

/**
* Test gutenberg_get_minified_styles().
*/
public function test_gutenberg_get_minified_styles() {
$cases = array(
array(
'in' => '
/**
* Comment
*/
.foo {
bar: 1;
}
',
'out' => '.foo{bar:1}',
),
array(
'in' => '/* Comment */#foo{content:" "; bar: 0;
}',
'out' => '#foo{content:" ";bar:0}',
),
);

foreach ( $cases as $case ) {
$this->assertSame(
gutenberg_get_minified_styles( $case['in'] ),
$case['out']
);
}
}
}

0 comments on commit 0e90abf

Please sign in to comment.