From e85ccb5b500690d87bb276a33a1cf35a52ba984f Mon Sep 17 00:00:00 2001 From: BE-Webdesign Date: Fri, 16 Jun 2017 15:57:32 -0400 Subject: [PATCH] Front end styling for blocks. Came across some interesting hurdles: 1. Block names most likely need to be registered server side in addition to client side. I forgot to write down the other ones lol. This PR seeks to add two different features and maybe should be split into two seperate PRs. Function 1: Dynamically break any blocks.scss files into a seperate file, so any default blocks styles which need to be displayed in both the editor and the theme, can be used. This is only currently used for adding gallery columns. Function 2: Adds an api for registering additional styles and scripts for blocks, to the theme, as well as to the editor itself. A low level API `register_block_assets()` is introduced as the backbone to some of the easier to use functions like: gutenberg_add_block_editor_style(), which mirrors the use of enqueue styles. The loading of these scripts and styles is handle automatically, and I think the end developer experience is already pretty good. Currently scripts can be only registered to blocks that have been previously registered. If the block is not present a _doing_it_wront() is thrown to help guide the programmer. **Testing Instructions** 1. Create a gallery block on the backend with two columns. Verify that the columns display correctly, and then on the front end of that post verify that the same gallery columns style applies. 2. Use the block style registry for testing additional styles being added. For ease, you can use the example provided above, but I recommend taking everything for a spin. --- blocks/library/gallery/blocks.scss | 44 ++ blocks/library/gallery/index.js | 2 + blocks/library/gallery/style.scss | 39 -- gutenberg.php | 1 + lib/blocks.php | 286 +++++++++++++ lib/blocks/quote.php | 8 + lib/client-assets.php | 62 ++- phpunit/class-asset-registration-test.php | 492 ++++++++++++++++++++++ webpack.config.js | 39 +- 9 files changed, 929 insertions(+), 44 deletions(-) create mode 100644 blocks/library/gallery/blocks.scss create mode 100644 lib/blocks/quote.php create mode 100644 phpunit/class-asset-registration-test.php diff --git a/blocks/library/gallery/blocks.scss b/blocks/library/gallery/blocks.scss new file mode 100644 index 00000000000000..394b04eb23855c --- /dev/null +++ b/blocks/library/gallery/blocks.scss @@ -0,0 +1,44 @@ +/** + * any blocks.scss will be split out into a seperate blocks/build/blocks.css + * + * This split is useful for enqueing onto the front end. + */ + +.blocks-gallery { + display: flex; + flex-wrap: wrap; + + .blocks-gallery-image { + flex-grow: 1; + margin: 8px; + + img { + max-width: 100%; + } + } + + &.columns-1 figure { + width: calc(100% / 1 - 2 * 8px); + } + &.columns-2 figure { + width: calc(100% / 2 - 3 * 8px); + } + &.columns-3 figure { + width: calc(100% / 3 - 4 * 8px); + } + &.columns-4 figure { + width: calc(100% / 4 - 5 * 8px); + } + &.columns-5 figure { + width: calc(100% / 5 - 6 * 8px); + } + &.columns-6 figure { + width: calc(100% / 6 - 7 * 8px); + } + &.columns-7 figure { + width: calc(100% / 7 - 8 * 8px); + } + &.columns-8 figure { + width: calc(100% / 8 - 9 * 8px); + } +} diff --git a/blocks/library/gallery/index.js b/blocks/library/gallery/index.js index 3de6361aafd436..5b3b343fb3b4b8 100644 --- a/blocks/library/gallery/index.js +++ b/blocks/library/gallery/index.js @@ -2,7 +2,9 @@ * Internal dependencies */ import { __ } from 'i18n'; +import './blocks.scss'; import './style.scss'; + import { registerBlockType, query as hpq } from '../../api'; import { Fill } from 'react-slot-fill'; diff --git a/blocks/library/gallery/style.scss b/blocks/library/gallery/style.scss index 709eeee2fa604c..cbe0e8e3017170 100644 --- a/blocks/library/gallery/style.scss +++ b/blocks/library/gallery/style.scss @@ -1,43 +1,4 @@ -.blocks-gallery { - display: flex; - flex-wrap: wrap; - - .blocks-gallery-image { - flex-grow: 1; - margin: 8px; - - img { - max-width: 100%; - } - } - - &.columns-1 figure { - width: calc(100% / 1 - 2 * 8px); - } - &.columns-2 figure { - width: calc(100% / 2 - 3 * 8px); - } - &.columns-3 figure { - width: calc(100% / 3 - 4 * 8px); - } - &.columns-4 figure { - width: calc(100% / 4 - 5 * 8px); - } - &.columns-5 figure { - width: calc(100% / 5 - 6 * 8px); - } - &.columns-6 figure { - width: calc(100% / 6 - 7 * 8px); - } - &.columns-7 figure { - width: calc(100% / 7 - 8 * 8px); - } - &.columns-8 figure { - width: calc(100% / 8 - 9 * 8px); - } -} - .blocks-gallery.is-placeholder { margin: -15px; padding: 6em 0; diff --git a/gutenberg.php b/gutenberg.php index dc89d835355a05..49cd3ab4bca261 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -20,4 +20,5 @@ require_once dirname( __FILE__ ) . '/lib/register.php'; // Register server-side code for individual blocks. +require_once dirname( __FILE__ ) . '/lib/blocks/quote.php'; require_once dirname( __FILE__ ) . '/lib/blocks/latest-posts.php'; diff --git a/lib/blocks.php b/lib/blocks.php index bffc2f16453968..6642bb8349357c 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -128,3 +128,289 @@ function do_blocks( $content ) { return $new_content; } add_filter( 'the_content', 'do_blocks', 10 ); // BEFORE do_shortcode(). + +/** + * The low level API for registering assets to be loaded with a block. + * + * @param string $name Name of already registered block you want to add assets to. + * @param array $assets Array of asset data. It follows the following format: + * array( + * // Location to load. + * 'editor' => array( + * 'scripts' => array( + * array( + * 'handle' => 'name of script to enqueue', + * 'src' => 'url to resource', + * 'deps' => array() of dependencies, + * 'ver' => version of resource, + * 'in_footer' => any specific media restrictions, + * ), + * ), + * 'styles' => array( + * array( + * 'handle' => 'name of style to enqueue', + * 'src' => 'url to resource', + * 'deps' => array() of dependencies, + * 'ver' => version of resource, + * 'media' => any specific media restrictions, + * ), + * ), + * ), + * 'theme' => array( + * // Same as above. + * ), + * ); + * Each individual asset is defined by an array matching the callback + * parameters to the matching wp_enqueue_{ script|style } function. + * @return array Array of asset data for the block, after registering. + */ +function register_block_assets( $name, $assets ) { + global $wp_registered_blocks; + if ( ! isset( $wp_registered_blocks[ $name ] ) ) { + /* translators: 1: block name */ + $message = sprintf( __( 'Block "%s" is not registered. It is possible you called this before it was registered.' ), $name ); + _doing_it_wrong( __FUNCTION__, $message, '0.1.0' ); + return false; + } + + // Check to see if assets have not been registered. + if ( ! isset( $wp_registered_blocks[ $name ]['assets'] ) ) { + $wp_registered_blocks[ $name ]['assets'] = array(); + } + + $wp_registered_blocks[ $name ]['assets'] = gutenberg_merge_assets( $wp_registered_blocks[ $name ]['assets'], $assets ); + return $wp_registered_blocks[ $name ]['assets']; +} + +/** + * Currently a wrapper for array_merge_recursive(). + * + * Lifted into a function so validation can be more easily added. + * + * @param array $current_assets Array of current assets. + * @param array $new_assets Array of new assets. + * @return array Array of merged assets. + */ +function gutenberg_merge_assets( $current_assets, $new_assets ) { + return array_merge_recursive( $current_assets, $new_assets ); +} + +/** + * Adds assets to be displayed in the theme. + * + * @param string $name Name of the block to register to. + * @param array $assets Array of new assets. + * + * @return array Array of asset data for block. + */ +function gutenberg_register_block_theme_assets( $name, $assets ) { + $theme_assets = array( + 'theme' => $assets, + ); + return register_block_assets( $name, $theme_assets ); +} + +/** + * Add assets to be displayed in the editor. + * + * @param string $name Name of the block to register to. + * @param array $assets Array of new assets. + * + * @return array Array of asset data for block. + */ +function gutenberg_register_block_editor_assets( $name, $assets ) { + $editor_assets = array( + 'editor' => $assets, + ); + return register_block_assets( $name, $editor_assets ); +} + +/** + * Add styles to be displayed in the editor. + * + * @param string $name Name of the block to register to. + * @param array $styles Array of new styles data. + * + * @return array Array of asset data for block. + */ +function gutenberg_register_block_editor_styles( $name, $styles ) { + $editor_styles = array( + 'styles' => $styles, + ); + return gutenberg_register_block_editor_assets( $name, $editor_styles ); +} + +/** + * Add styles to be displayed in the theme. + * + * @param string $name Name of the block to register to. + * @param array $styles Array of new styles data. + * + * @return array Array of asset data for block. + */ +function gutenberg_register_block_theme_styles( $name, $styles ) { + $editor_styles = array( + 'styles' => $styles, + ); + return gutenberg_register_block_theme_assets( $name, $editor_styles ); +} + +/** + * Add scripts to be displayed in the editor. + * + * @param string $name Name of the block to register to. + * @param array $scripts Array of new scripts data. + * + * @return array Array of asset data for block. + */ +function gutenberg_register_block_editor_scripts( $name, $scripts ) { + $editor_scripts = array( + 'scripts' => $scripts, + ); + return gutenberg_register_block_editor_assets( $name, $editor_scripts ); +} + +/** + * Add scripts to be displayed in the theme. + * + * @param string $name Name of the block to register to. + * @param array $scripts Array of new scripts data. + * + * @return array Array of asset data for block. + */ +function gutenberg_register_block_theme_scripts( $name, $scripts ) { + $theme_scripts = array( + 'scripts' => $scripts, + ); + return gutenberg_register_block_theme_assets( $name, $theme_scripts ); +} + +/** + * Adds a block style to the editor. + * + * Should use the same function signature as wp_register_script() after $name. + * + * @param string $name Block name to register to. + * @param string $handle (Required) Name of the script. Should be unique. + * @param string $src (Required) Full URL of the script, + * or path of the script relative to the WordPress root directory. + * @param array $deps (Optional) An array of registered script + * handles this script depends on. Default value: array(). + * @param string|bool|null $version (Optional) String specifying script + * version number, if it has one, which is added to the URL as a query string + * for cache busting purposes. If version is set to false, a version number is + * automatically added equal to current installed WordPress version. + * If set to null, no version is added. Default value: false. + * @param string $media (Optional) Targeted medium. Default value: 'all'. + * + * @return array Array of asset data for block. + */ +function gutenberg_add_block_editor_style( $name, $handle, $src, $deps = array(), $version = false, $media = 'all' ) { + $style = array( + 'handle' => $handle, + 'src' => $src, + 'deps' => $deps, + 'ver' => $version, + 'media' => $media, + ); + + return gutenberg_register_block_editor_styles( $name, array( $style ) ); +} + +/** + * Adds a block style to the theme. + * + * Should use the same function signature as wp_register_script() after $name. + * + * @param string $name Block name to register to. + * @param string $handle (Required) Name of the script. Should be unique. + * @param string $src (Required) Full URL of the script, + * or path of the script relative to the WordPress root directory. + * @param array $deps (Optional) An array of registered script + * handles this script depends on. Default value: array(). + * @param string|bool|null $version (Optional) String specifying script + * version number, if it has one, which is added to the URL as a query string + * for cache busting purposes. If version is set to false, a version number is + * automatically added equal to current installed WordPress version. + * If set to null, no version is added. Default value: false. + * @param string $media (Optional) Targeted medium. Default value: 'all'. + * + * @return array Array of asset data for block. + */ +function gutenberg_add_block_theme_style( $name, $handle, $src, $deps = array(), $version = false, $media = 'all' ) { + $style = array( + 'handle' => $handle, + 'src' => $src, + 'deps' => $deps, + 'ver' => $version, + 'media' => $media, + ); + + return gutenberg_register_block_theme_styles( $name, array( $style ) ); +} + +/** + * Adds a block script to the editor. + * + * Should use the same function signature as wp_register_script() after $name. + * + * @param string $name Block name to register to. + * @param string $handle (Required) Name of the script. Should be unique. + * @param string $src (Required) Full URL of the script, + * or path of the script relative to the WordPress root directory. + * @param array $deps (Optional) An array of registered script + * handles this script depends on. Default value: array(). + * @param string|bool|null $version (Optional) String specifying script + * version number, if it has one, which is added to the URL as a query string + * for cache busting purposes. If version is set to false, a version number is + * automatically added equal to current installed WordPress version. + * If set to null, no version is added. Default value: false. + * @param bool $in_footer (Optional) Whether to enqueue the script + * before instead of in the . Default 'false'. Default value: false. + * + * @return array Array of asset data for block. + */ +function gutenberg_add_block_editor_script( $name, $handle, $src, $deps = array(), $version = false, $in_footer = false ) { + $script = array( + 'handle' => $handle, + 'src' => $src, + 'deps' => $deps, + 'ver' => $version, + 'in_footer' => $in_footer, + ); + + return gutenberg_register_block_editor_scripts( $name, array( $script ) ); +} + +/** + * Adds a block script to the theme. + * + * Should use the same function signature as wp_register_script() after $name. + * + * @param string $name Block name to register to. + * @param string $handle (Required) Name of the script. Should be unique. + * @param string $src (Required) Full URL of the script, + * or path of the script relative to the WordPress root directory. + * @param array $deps (Optional) An array of registered script + * handles this script depends on. Default value: array(). + * @param string|bool|null $version (Optional) String specifying script + * version number, if it has one, which is added to the URL as a query string + * for cache busting purposes. If version is set to false, a version number is + * automatically added equal to current installed WordPress version. + * If set to null, no version is added. Default value: false. + * @param bool $in_footer (Optional) Whether to enqueue the script + * before instead of in the . Default 'false'. Default value: false. + * + * @return array Array of asset data for block. + */ +function gutenberg_add_block_theme_script( $name, $handle, $src, $deps = array(), $version = false, $in_footer = false ) { + $script = array( + 'handle' => $handle, + 'src' => $src, + 'deps' => $deps, + 'ver' => $version, + 'in_footer' => $in_footer, + ); + + return gutenberg_register_block_theme_scripts( $name, array( $script ) ); +} diff --git a/lib/blocks/quote.php b/lib/blocks/quote.php new file mode 100644 index 00000000000000..128be3a4ed343a --- /dev/null +++ b/lib/blocks/quote.php @@ -0,0 +1,8 @@ + $settings ) { + // If there are assets registered see if any theme assets are registered. + if ( isset( $settings['assets'] ) && isset( $settings['assets'][ $location ] ) ) { + $location_assets = $settings['assets'][ $location ]; + + // Handle scripts. + if ( isset( $location_assets['scripts'] ) && is_array( $location_assets['scripts'] ) ) { + foreach ( $location_assets['scripts'] as $script ) { + wp_enqueue_style( $script['handle'], $script['src'], $script['deps'], $script['ver'], $script['in_footer'] ); + } + } + + // Handle styles. + if ( isset( $location_assets['styles'] ) && is_array( $location_assets['styles'] ) ) { + foreach ( $location_assets['styles'] as $style ) { + wp_enqueue_style( $style['handle'], $style['src'], $style['deps'], $style['ver'], $style['media'] ); + } + } + } + } +} diff --git a/phpunit/class-asset-registration-test.php b/phpunit/class-asset-registration-test.php new file mode 100644 index 00000000000000..82a3189435a5e8 --- /dev/null +++ b/phpunit/class-asset-registration-test.php @@ -0,0 +1,492 @@ +assertFalse( $result ); + } + + /** + * Test registering to a block with empty assets. + */ + function test_registering_assets_to_registered_block_without_assets() { + $assets = array( + 'theme' => array( + 'styles' => array( + array( + 'handle' => 'core/does-not-exist', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + $result = register_block_assets( 'core/text', $assets ); + + global $wp_registered_blocks; + + $this->assertEquals( $assets, $wp_registered_blocks['core/text']['assets'] ); + } + + /** + * Test registering to a block with already existing assets. + */ + function test_registering_assets_to_registered_block_with_existing_assets() { + $assets_1 = array( + 'theme' => array( + 'styles' => array( + array( + 'handle' => 'core/does-not-exist', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + register_block_assets( 'core/text', $assets_1 ); + + $assets_2 = array( + 'theme' => array( + 'styles' => array( + array( + 'handle' => 'core/does-not-exist', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + $result = register_block_assets( 'core/text', $assets_2 ); + + $expected = array( + 'theme' => array( + 'styles' => array( + array( + 'handle' => 'core/does-not-exist', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + array( + 'handle' => 'core/does-not-exist', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + $this->assertEquals( $expected, $result ); + } + + /** + * Should add an editor style asset for the block. + */ + function test_gutenberg_add_block_editor_style() { + $expected = array( + 'editor' => array( + 'styles' => array( + array( + 'handle' => 'my-handle', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => false, + 'media' => 'all', + ), + ), + ), + ); + gutenberg_add_block_editor_style( 'core/text', 'my-handle', 'https://wordpress.org/is-the-best' ); + + global $wp_registered_blocks; + + $this->assertEquals( $expected, $wp_registered_blocks['core/text']['assets'] ); + } + + /** + * Should add an editor style asset for the block. + */ + function test_gutenberg_add_block_theme_style() { + $expected = array( + 'theme' => array( + 'styles' => array( + array( + 'handle' => 'my-handle', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => false, + 'media' => 'all', + ), + ), + ), + ); + gutenberg_add_block_theme_style( 'core/text', 'my-handle', 'https://wordpress.org/is-the-best' ); + + global $wp_registered_blocks; + + $this->assertEquals( $expected, $wp_registered_blocks['core/text']['assets'] ); + } + + /** + * Should add an editor script asset for the block. + */ + function test_gutenberg_add_block_editor_script() { + $expected = array( + 'editor' => array( + 'scripts' => array( + array( + 'handle' => 'my-handle', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => false, + 'in_footer' => false, + ), + ), + ), + ); + gutenberg_add_block_editor_script( 'core/text', 'my-handle', 'https://wordpress.org/is-the-best' ); + + global $wp_registered_blocks; + + $this->assertEquals( $expected, $wp_registered_blocks['core/text']['assets'] ); + } + + /** + * Should add an editor script asset for the block. + */ + function test_gutenberg_add_block_theme_script() { + $expected = array( + 'theme' => array( + 'scripts' => array( + array( + 'handle' => 'my-handle', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => false, + 'in_footer' => false, + ), + ), + ), + ); + gutenberg_add_block_theme_script( 'core/text', 'my-handle', 'https://wordpress.org/is-the-best' ); + + global $wp_registered_blocks; + + $this->assertEquals( $expected, $wp_registered_blocks['core/text']['assets'] ); + } + + /** + * Should merge asset data into array. + */ + function test_merging_to_empty_assets() { + $current_assets = array(); + $assets = array( + 'theme' => array( + 'styles' => array( + array( + 'handle' => 'core/does-not-exist', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + + $result = gutenberg_merge_assets( $current_assets, $assets ); + $expected = array( + 'theme' => array( + 'styles' => array( + array( + 'handle' => 'core/does-not-exist', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + + $this->assertEquals( $expected, $result ); + } + + /** + * Should merge asset data into existing data, creating multiple styles to be enqueued. + */ + function test_merging_to_existing_assets() { + $current_assets = array( + 'theme' => array( + 'styles' => array( + array( + 'handle' => 'style 1', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + $assets = array( + 'theme' => array( + 'styles' => array( + array( + 'handle' => 'style 2', + 'src' => 'https://wordpress.org/is-wonderful', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + + $result = gutenberg_merge_assets( $current_assets, $assets ); + $expected = array( + 'theme' => array( + 'styles' => array( + array( + 'handle' => 'style 1', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + array( + 'handle' => 'style 2', + 'src' => 'https://wordpress.org/is-wonderful', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + + $this->assertEquals( $expected, $result ); + } + + /** + * Should merge scripts and style assets to match the expected output. + */ + function test_merging_new_scripts_and_styles() { + $current_assets = array( + 'theme' => array( + 'styles' => array( + array( + 'handle' => 'style 1', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + $assets = array( + 'theme' => array( + 'scripts' => array( + array( + 'handle' => 'script 1', + 'src' => 'https://wordpress.org/is-neat', + 'deps' => array(), + 'ver' => null, + 'in_footer' => null, + ), + ), + 'styles' => array( + array( + 'handle' => 'style 2', + 'src' => 'https://wordpress.org/is-wonderful', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + + $result = gutenberg_merge_assets( $current_assets, $assets ); + $expected = array( + 'theme' => array( + 'scripts' => array( + array( + 'handle' => 'script 1', + 'src' => 'https://wordpress.org/is-neat', + 'deps' => array(), + 'ver' => null, + 'in_footer' => null, + ), + ), + 'styles' => array( + array( + 'handle' => 'style 1', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + array( + 'handle' => 'style 2', + 'src' => 'https://wordpress.org/is-wonderful', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + + $this->assertEquals( $expected, $result ); + } + + /** + * Should merge scripts and style assets across multiple calls to match the expected output. + */ + function test_merging_across_multiple_calls() { + $current_assets = array( + 'theme' => array( + 'styles' => array( + array( + 'handle' => 'style 1', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + $assets_1 = array( + 'theme' => array( + 'scripts' => array( + array( + 'handle' => 'script 1', + 'src' => 'https://wordpress.org/is-neat', + 'deps' => array(), + 'ver' => null, + 'in_footer' => null, + ), + ), + 'styles' => array( + array( + 'handle' => 'style 2', + 'src' => 'https://wordpress.org/is-wonderful', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + $assets_2 = array( + 'theme' => array( + 'styles' => array( + array( + 'handle' => 'style 3', + 'src' => 'https://wordpress.org/is-goofy', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + 'editor' => array( + 'styles' => array( + array( + 'handle' => 'style 4', + 'src' => 'https://wordpress.org/is-free', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + + $first_merge = gutenberg_merge_assets( $current_assets, $assets_1 ); + $result = gutenberg_merge_assets( $first_merge, $assets_2 ); + $expected = array( + 'theme' => array( + 'styles' => array( + array( + 'handle' => 'style 1', + 'src' => 'https://wordpress.org/is-the-best', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + array( + 'handle' => 'style 2', + 'src' => 'https://wordpress.org/is-wonderful', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + array( + 'handle' => 'style 3', + 'src' => 'https://wordpress.org/is-goofy', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + 'scripts' => array( + array( + 'handle' => 'script 1', + 'src' => 'https://wordpress.org/is-neat', + 'deps' => array(), + 'ver' => null, + 'in_footer' => null, + ), + ), + ), + 'editor' => array( + 'styles' => array( + array( + 'handle' => 'style 4', + 'src' => 'https://wordpress.org/is-free', + 'deps' => array(), + 'ver' => null, + 'media' => null, + ), + ), + ), + ); + + $this->assertEquals( $expected, $result ); + } +} diff --git a/webpack.config.js b/webpack.config.js index c20462f582084c..bcb064298a75a1 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -30,6 +30,16 @@ entryPointNames.forEach( entryPointName => { }; } ); +// Main CSS loader. +const MainCSSExtractTextPlugin = new ExtractTextPlugin( { + filename: './[name]/build/style.css', +} ); + +// CSS loader for front end style building. +const BlockCSSExtractTextPlugin = new ExtractTextPlugin( { + filename: './blocks/build/blocks.css', +} ); + const config = { entry: entryPointNames.reduce( ( memo, entryPointName ) => { memo[ entryPointName ] = './' + entryPointName + '/index.js'; @@ -64,9 +74,31 @@ const config = { exclude: /node_modules/, use: 'babel-loader', }, + { + test: /blocks\.s?css$/, + include: [ + /blocks/, + ], + use: BlockCSSExtractTextPlugin.extract( { + use: [ + { loader: 'raw-loader' }, + { loader: 'postcss-loader' }, + { + loader: 'sass-loader', + query: { + outputStyle: 'production' === process.env.NODE_ENV ? + 'compressed' : 'nested', + }, + }, + ], + } ), + }, { test: /\.s?css$/, - use: ExtractTextPlugin.extract( { + exclude: [ + /blocks\.s?css$/, + ], + use: MainCSSExtractTextPlugin.extract( { use: [ { loader: 'raw-loader' }, { loader: 'postcss-loader' }, @@ -88,9 +120,8 @@ const config = { new webpack.DefinePlugin( { 'process.env.NODE_ENV': JSON.stringify( process.env.NODE_ENV || 'development' ), } ), - new ExtractTextPlugin( { - filename: './[name]/build/style.css', - } ), + BlockCSSExtractTextPlugin, + MainCSSExtractTextPlugin, new webpack.LoaderOptionsPlugin( { minimize: process.env.NODE_ENV === 'production', debug: process.env.NODE_ENV !== 'production',