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

Script Modules: Centralize (re)registration #65460

Merged
merged 20 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 3 additions & 2 deletions .github/workflows/unit-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ jobs:
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: build-assets
path: ./build/
path: |
./build/
./build-module/

test-php:
name: PHP ${{ matrix.php }}${{ matrix.multisite && ' multisite' || '' }}${{ matrix.wordpress != '' && format( ' (WP {0}) ', matrix.wordpress ) || '' }} on ubuntu-latest
Expand Down Expand Up @@ -212,7 +214,6 @@ jobs:
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: build-assets
path: ./build

- name: Docker debug information
run: |
Expand Down
3 changes: 3 additions & 0 deletions backport-changelog/6.7/7360.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
https://github.com/WordPress/wordpress-develop/pull/7360

* https://github.com/WordPress/gutenberg/pull/65460
50 changes: 50 additions & 0 deletions lib/client-assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,56 @@ function gutenberg_register_vendor_scripts( $scripts ) {
}
add_action( 'wp_default_scripts', 'gutenberg_register_vendor_scripts' );

/**
* Registers or re-registers Gutenberg Script Modules.
*
* Script modules that are registered by Core will be re-registered by Gutenberg.
*
* @since 19.3.0
*/
function gutenberg_default_script_modules() {
/*
* Expects multidimensional array like:
*
* 'interactivity/index.min.js' => array('dependencies' => array(…), 'version' => '…'),
* 'interactivity/debug.min.js' => array('dependencies' => array(…), 'version' => '…'),
* 'interactivity-router/index.min.js' => …
*/
$assets = include gutenberg_dir_path() . '/build-module/assets.php';

foreach ( $assets as $file_name => $script_module_data ) {
/*
* Build the WordPress Script Module ID from the file name.
* Prepend `@wordpress/` and remove extensions and `/index` if present:
* - interactivity/index.min.js => @wordpress/interactivity
* - interactivity/debug.min.js => @wordpress/interactivity/debug
* - block-library/query/view.js => @wordpress/block-library/query/view
*/
$script_module_id = '@wordpress/' . preg_replace( '~(?:/index)?\.min\.js$~D', '', $file_name, 1 );
switch ( $script_module_id ) {
/*
* Interactivity exposes two entrypoints, "/index" and "/debug".
* "/debug" should replalce "/index" in devlopment.
*/
case '@wordpress/interactivity/debug':
if ( ! SCRIPT_DEBUG ) {
continue 2;
}
$script_module_id = '@wordpress/interactivity';
break;
case '@wordpress/interactivity':
if ( SCRIPT_DEBUG ) {
continue 2;
}
break;
}

$path = gutenberg_url( "build-module/{$file_name}" );
Copy link
Member

Choose a reason for hiding this comment

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

There is a slight change that needs to get incorporated here. There should be a different file served depending on SCRIPT_DEBUG:

  • when true: .js
  • when false: .min.js

Copy link
Member

Choose a reason for hiding this comment

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

I'm not that sure anymore after looking at how scripts for packages are handled:

foreach ( glob( gutenberg_dir_path() . 'build/*/index.min.js' ) as $path ) {
// Prefix `wp-` to package directory to get script handle.
// For example, `…/build/a11y/index.min.js` becomes `wp-a11y`.
$handle = 'wp-' . basename( dirname( $path ) );
// Replace extension with `.asset.php` to find the generated dependencies file.
$asset_file = substr( $path, 0, -( strlen( '.js' ) ) ) . '.asset.php';
$asset = file_exists( $asset_file )
? require $asset_file
: null;
$dependencies = isset( $asset['dependencies'] ) ? $asset['dependencies'] : array();
$version = isset( $asset['version'] ) ? $asset['version'] : $default_version;
// Add dependencies that cannot be detected and generated by build tools.
switch ( $handle ) {
case 'wp-block-library':
if (
! gutenberg_is_experiment_enabled( 'gutenberg-no-tinymce' ) ||
! empty( $_GET['requiresTinymce'] ) ||
gutenberg_post_being_edited_requires_classic_block()
) {
array_push( $dependencies, 'editor' );
}
break;
case 'wp-edit-post':
array_push( $dependencies, 'media-models', 'media-views', 'postbox' );
break;
case 'wp-edit-site':
array_push( $dependencies, 'wp-dom-ready' );
break;
case 'wp-preferences':
array_push( $dependencies, 'wp-preferences-persistence' );
break;
}
// Get the path from Gutenberg directory as expected by `gutenberg_url`.
$gutenberg_path = substr( $path, strlen( gutenberg_dir_path() ) );
gutenberg_override_script(
$scripts,
$handle,
gutenberg_url( $gutenberg_path ),
$dependencies,
$version,
true
);
}

Copy link
Member Author

Choose a reason for hiding this comment

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

👍 Done.

Copy link
Member

Choose a reason for hiding this comment

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

I didn't have the latest version of the branch 🙈

This is what I see now with npm run dev:

Screenshot 2024-09-20 at 12 39 03 Screenshot 2024-09-20 at 12 40 06

I still do not think I understand it fully. .min.js is always produced when you use npm run dev and npm run build. mode === 'production' && new ReadableJsAssetsWebpackPlugin(), means that .js gets only generated for production builds - npm run build. From the docs of the webpack plugin:

Generate a readable non-minified JS file for each .min.js asset.

The end result is that for each JS entrypoint, we get a set of readable and non-minimized .js file and a minimized .min.js. This allows Gutenberg to follow the WordPress convention of adding a .min.js suffix to minimized JS files, while still providing a readable and unminized files that play well with the WordPress i18n machinery.

I'm still puzzled why there is no SCRIPT_DEBUG involved like in WP core.

Copy link
Member

Choose a reason for hiding this comment

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

I think we can remove 44da0b0 for now and ship it all as is.

Copy link
Member

@gziolo gziolo Sep 20, 2024

Choose a reason for hiding this comment

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

The same folder after npm run build:

Screenshot 2024-09-20 at 12 49 23

Notice .js and .min.js files get created. For npm run dev I see only .min.js files 🤷🏻 In effect, it behaves like in debug mode. However, once the plugin gets released, there is no longer a way to use the debug version. In fact, it probably doesn't make too much sense, because .js file is built with production mode.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it's confusing. When doing a development build, .min.js files are produced but they're not minified. The SCRIPT_DEBUG doesn't change the files Gutenberg uses.

I've reverted the .min.js/.js changes.

wp_register_script_module( $script_module_id, $path, $script_module_data['dependencies'], $script_module_data['version'] );
}
}
remove_action( 'wp_default_scripts', 'wp_default_script_modules' );
add_action( 'wp_default_scripts', 'gutenberg_default_script_modules' );

/*
* Always remove the Core action hook while gutenberg_enqueue_stored_styles() exists to avoid styles being printed twice.
Expand Down
25 changes: 2 additions & 23 deletions lib/experimental/script-modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,26 +239,5 @@ function gutenberg_a11y_script_module_html() {
. '<div id="a11y-speak-polite" class="a11y-speak-region" aria-live="polite" aria-relevant="additions text" aria-atomic="true"></div>'
. '</div>';
}

/**
* Registers Gutenberg Script Modules.
*
* @since 19.3
*/
function gutenberg_register_script_modules() {
// When in production, use the plugin's version as the default asset version;
// else (for development or test) default to use the current time.
$default_version = defined( 'GUTENBERG_VERSION' ) && ! SCRIPT_DEBUG ? GUTENBERG_VERSION : time();

wp_deregister_script_module( '@wordpress/a11y' );
wp_register_script_module(
'@wordpress/a11y',
gutenberg_url( 'build-module/a11y/index.min.js' ),
array(),
$default_version
);

add_action( 'wp_footer', 'gutenberg_a11y_script_module_html' );
add_action( 'admin_footer', 'gutenberg_a11y_script_module_html' );
}
add_action( 'init', 'gutenberg_register_script_modules' );
add_action( 'wp_footer', 'gutenberg_a11y_script_module_html' );
add_action( 'admin_footer', 'gutenberg_a11y_script_module_html' );
31 changes: 0 additions & 31 deletions lib/interactivity-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,6 @@
* @package gutenberg
*/

/**
* Deregisters the Core Interactivity API Modules and replace them
* with the ones from the Gutenberg plugin.
*/
function gutenberg_reregister_interactivity_script_modules() {
$default_version = defined( 'GUTENBERG_VERSION' ) && ! SCRIPT_DEBUG ? GUTENBERG_VERSION : time();
wp_deregister_script_module( '@wordpress/interactivity' );
wp_deregister_script_module( '@wordpress/interactivity-router' );

wp_register_script_module(
'@wordpress/interactivity',
gutenberg_url( '/build-module/' . ( SCRIPT_DEBUG ? 'interactivity/debug.min.js' : 'interactivity/index.min.js' ) ),
array(),
$default_version
);

wp_register_script_module(
'@wordpress/interactivity-router',
gutenberg_url( '/build-module/interactivity-router/index.min.js' ),
array(
array(
'id' => '@wordpress/a11y',
'import' => 'dynamic',
),
'@wordpress/interactivity',
),
$default_version
);
}
add_action( 'init', 'gutenberg_reregister_interactivity_script_modules' );

/**
* Adds script data to the interactivity-router script module.
*
Expand Down
13 changes: 1 addition & 12 deletions packages/block-library/src/file/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,7 @@
function render_block_core_file( $attributes, $content ) {
// If it's interactive, enqueue the script module and add the directives.
if ( ! empty( $attributes['displayPreview'] ) ) {
$suffix = wp_scripts_get_suffix();
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
$module_url = gutenberg_url( '/build-module/block-library/file/view.min.js' );
}

wp_register_script_module(
'@wordpress/block-library/file',
isset( $module_url ) ? $module_url : includes_url( "blocks/file/view{$suffix}.js" ),
array( '@wordpress/interactivity' ),
defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' )
);
wp_enqueue_script_module( '@wordpress/block-library/file' );
wp_enqueue_script_module( '@wordpress/block-library/file/view' );
Copy link
Member

Choose a reason for hiding this comment

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

Brilliant!


$processor = new WP_HTML_Tag_Processor( $content );
$processor->next_tag();
Expand Down
14 changes: 1 addition & 13 deletions packages/block-library/src/image/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,7 @@ function render_block_core_image( $attributes, $content, $block ) {
isset( $lightbox_settings['enabled'] ) &&
true === $lightbox_settings['enabled']
) {
$suffix = wp_scripts_get_suffix();
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
$module_url = gutenberg_url( '/build-module/block-library/image/view.min.js' );
}

wp_register_script_module(
'@wordpress/block-library/image',
isset( $module_url ) ? $module_url : includes_url( "blocks/image/view{$suffix}.js" ),
array( '@wordpress/interactivity' ),
defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' )
);

wp_enqueue_script_module( '@wordpress/block-library/image' );
wp_enqueue_script_module( '@wordpress/block-library/image/view' );

/*
* This render needs to happen in a filter with priority 15 to ensure that
Expand Down
13 changes: 1 addition & 12 deletions packages/block-library/src/navigation/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -622,18 +622,7 @@ private static function get_nav_element_directives( $is_interactive ) {
*/
private static function handle_view_script_module_loading( $attributes, $block, $inner_blocks ) {
if ( static::is_interactive( $attributes, $inner_blocks ) ) {
$suffix = wp_scripts_get_suffix();
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
$module_url = gutenberg_url( '/build-module/block-library/navigation/view.min.js' );
}

wp_register_script_module(
'@wordpress/block-library/navigation',
isset( $module_url ) ? $module_url : includes_url( "blocks/navigation/view{$suffix}.js" ),
array( '@wordpress/interactivity' ),
defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' )
);
wp_enqueue_script_module( '@wordpress/block-library/navigation' );
wp_enqueue_script_module( '@wordpress/block-library/navigation/view' );
}
}

Expand Down
22 changes: 1 addition & 21 deletions packages/block-library/src/query/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,7 @@ function render_block_core_query( $attributes, $content, $block ) {
// Enqueue the script module and add the necessary directives if the block is
// interactive.
if ( $is_interactive ) {
$suffix = wp_scripts_get_suffix();
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
$module_url = gutenberg_url( '/build-module/block-library/query/view.min.js' );
}

wp_register_script_module(
'@wordpress/block-library/query',
isset( $module_url ) ? $module_url : includes_url( "blocks/query/view{$suffix}.js" ),
array(
array(
'id' => '@wordpress/interactivity',
'import' => 'static',
),
array(
'id' => '@wordpress/interactivity-router',
'import' => 'dynamic',
),
),
defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' )
);
wp_enqueue_script_module( '@wordpress/block-library/query' );
wp_enqueue_script_module( '@wordpress/block-library/query/view' );

$p = new WP_HTML_Tag_Processor( $content );
if ( $p->next_tag() ) {
Expand Down
13 changes: 1 addition & 12 deletions packages/block-library/src/search/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,7 @@ function render_block_core_search( $attributes ) {
// If it's interactive, enqueue the script module and add the directives.
$is_expandable_searchfield = 'button-only' === $button_position;
if ( $is_expandable_searchfield ) {
$suffix = wp_scripts_get_suffix();
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
$module_url = gutenberg_url( '/build-module/block-library/search/view.min.js' );
}

wp_register_script_module(
'@wordpress/block-library/search',
isset( $module_url ) ? $module_url : includes_url( "blocks/search/view{$suffix}.js" ),
array( '@wordpress/interactivity' ),
defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' )
);
wp_enqueue_script_module( '@wordpress/block-library/search' );
wp_enqueue_script_module( '@wordpress/block-library/search/view' );

$input->set_attribute( 'data-wp-bind--aria-hidden', '!context.isSearchInputVisible' );
$input->set_attribute( 'data-wp-bind--tabindex', 'state.tabindex' );
Expand Down
12 changes: 9 additions & 3 deletions tools/webpack/script-modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@ module.exports = {
},
output: {
devtoolNamespace: 'wp',
filename: './build-module/[name].min.js',
filename: '[name].min.js',
library: {
type: 'module',
},
path: join( __dirname, '..', '..' ),
path: join( __dirname, '..', '..', 'build-module' ),
environment: { module: true },
module: true,
chunkFormat: 'module',
Expand All @@ -102,7 +102,13 @@ module.exports = {
resolve: {
extensions: [ '.js', '.ts', '.tsx' ],
},
plugins: [ ...plugins, new DependencyExtractionWebpackPlugin() ],
plugins: [
...plugins,
new DependencyExtractionWebpackPlugin( {
combineAssets: true,
combinedOutputFile: `./assets.php`,
Copy link
Member

Choose a reason for hiding this comment

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

Huge perf win! It will pay off over time. 👏

Copy link
Member

Choose a reason for hiding this comment

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

I was trying to remember why there are two versions in WP core:

https://github.com/WordPress/wordpress-develop/blob/35907da95151b45d197102ea4d69e10ad019cab9/tools/webpack/packages.js#L201

All good here. I figured out that in WP core, there are two parallel build processes - one for development and one for production, so they shouldn't be overridden. It isn't the case here.

Copy link
Member

Choose a reason for hiding this comment

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

On the second thought:

npm run dev

Screenshot 2024-09-20 at 12 14 31

npm run build

Screenshot 2024-09-20 at 12 19 54

Notice the file name difference .js vs .min.js.

} ),
],
watchOptions: {
ignored: [ '**/node_modules' ],
aggregateTimeout: 500,
Expand Down
Loading