From 39a11a85f520a8b36e433f97fb35e039ce7937f4 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 8 Oct 2024 16:10:13 +0200 Subject: [PATCH 01/42] Add "expose" logic to script modules This allows for script modules to be exposed in the import map regardless of being a dependency or enqueued. This will enable scripts to depend on script modules by requesting they be exposed. --- src/wp-includes/class-wp-script-modules.php | 33 ++++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/class-wp-script-modules.php b/src/wp-includes/class-wp-script-modules.php index dbfa038f8cbe2..4f9973236fecb 100644 --- a/src/wp-includes/class-wp-script-modules.php +++ b/src/wp-includes/class-wp-script-modules.php @@ -30,6 +30,18 @@ class WP_Script_Modules { */ private $enqueued_before_registered = array(); + /** + * Holds script module identifiers that have been requested for exposure. + * + * "Exposed" indicates that the script module should be exposed in the + * import map regardless of whether it is a dependency of another script + * module. + * + * @since 6.8.0 + * @var array + */ + private $exposed = array(); + /** * Tracks whether the @wordpress/a11y script module is available. * @@ -148,6 +160,17 @@ public function enqueue( string $id, string $src = '', array $deps = array(), $v } } + /** + * Marks the script module so it will be exposed in the import map. + * + * @since 6.8.0 + * + * @param string $id The identifier of the script module. + */ + public function expose( string $id ) { + $this->exposed[ $id ] = true; + } + /** * Unmarks the script module so it will no longer be enqueued in the page. * @@ -262,12 +285,14 @@ public function print_import_map() { * * @since 6.5.0 * - * @return array Array with an `imports` key mapping to an array of script module identifiers and their respective - * URLs, including the version query. + * @return array Array with an `imports` key mapping to an array of script + * module identifiers and their respective URLs, including + * the version query. */ private function get_import_map(): array { - $imports = array(); - foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ) ) as $id => $script_module ) { + $imports = array(); + $script_module_ids = array_unique( array_keys( $this->exposed ) + array_keys( $this->get_marked_for_enqueue() ) ); + foreach ( $this->get_dependencies( $script_module_ids ) as $id => $script_module ) { $imports[ $id ] = $this->get_src( $id ); } return array( 'imports' => $imports ); From 65fd1dfc7e34bda55a18ea912420367c1cfe2b74 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 8 Oct 2024 16:14:57 +0200 Subject: [PATCH 02/42] Make get_src return nullable --- src/wp-includes/class-wp-script-modules.php | 26 ++++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/class-wp-script-modules.php b/src/wp-includes/class-wp-script-modules.php index 4f9973236fecb..801ab09ef06d8 100644 --- a/src/wp-includes/class-wp-script-modules.php +++ b/src/wp-includes/class-wp-script-modules.php @@ -231,10 +231,15 @@ public function add_hooks() { */ public function print_enqueued_script_modules() { foreach ( $this->get_marked_for_enqueue() as $id => $script_module ) { + $src = $this->get_src( $id ); + if ( null === $src ) { + continue; + } + wp_print_script_tag( array( 'type' => 'module', - 'src' => $this->get_src( $id ), + 'src' => $src, 'id' => $id . '-js-module', ) ); @@ -251,11 +256,16 @@ public function print_enqueued_script_modules() { */ public function print_script_module_preloads() { foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ), array( 'static' ) ) as $id => $script_module ) { + $src = $this->get_src( $id ); + if ( null === $src ) { + continue; + } + // Don't preload if it's marked for enqueue. if ( true !== $script_module['enqueue'] ) { echo sprintf( '', - esc_url( $this->get_src( $id ) ), + esc_url( $src ), esc_attr( $id . '-js-modulepreload' ) ); } @@ -293,7 +303,11 @@ private function get_import_map(): array { $imports = array(); $script_module_ids = array_unique( array_keys( $this->exposed ) + array_keys( $this->get_marked_for_enqueue() ) ); foreach ( $this->get_dependencies( $script_module_ids ) as $id => $script_module ) { - $imports[ $id ] = $this->get_src( $id ); + $src = $this->get_src( $id ); + if ( null === $src ) { + continue; + } + $imports[ $id ] = $src; } return array( 'imports' => $imports ); } @@ -360,11 +374,11 @@ function ( $dependency_script_modules, $id ) use ( $import_types ) { * @since 6.5.0 * * @param string $id The script module identifier. - * @return string The script module src with a version if relevant. + * @return string|null The script module src with a version if relevant. */ - private function get_src( string $id ): string { + private function get_src( string $id ): ?string { if ( ! isset( $this->registered[ $id ] ) ) { - return ''; + return null; } $script_module = $this->registered[ $id ]; From 843e1e0a077cc7f7c02ed9af00d3d6a72319575b Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Mon, 16 Dec 2024 17:14:55 +0100 Subject: [PATCH 03/42] Rework, rename, add tests --- src/wp-includes/class-wp-script-modules.php | 37 ++++++++++++++----- .../tests/script-modules/wpScriptModules.php | 32 ++++++++++++++-- 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/src/wp-includes/class-wp-script-modules.php b/src/wp-includes/class-wp-script-modules.php index 801ab09ef06d8..b1544813bff27 100644 --- a/src/wp-includes/class-wp-script-modules.php +++ b/src/wp-includes/class-wp-script-modules.php @@ -31,16 +31,20 @@ class WP_Script_Modules { private $enqueued_before_registered = array(); /** - * Holds script module identifiers that have been requested for exposure. + * Holds script module identifiers that have been marked for inclusion in the import map. * - * "Exposed" indicates that the script module should be exposed in the - * import map regardless of whether it is a dependency of another script - * module. + * A script module that appears here should be include in the import map regardless of + * whether it is a dependency of another script module. + * + * The values in this array are always `null`. The presence of a Module IDs + * as an array key marks the script module for inclusion in the import map. + * Different values are reserved for possible future use. * * @since 6.8.0 - * @var array + * + * @var array */ - private $exposed = array(); + private $marked_for_inclusion = array(); /** * Tracks whether the @wordpress/a11y script module is available. @@ -161,14 +165,18 @@ public function enqueue( string $id, string $src = '', array $deps = array(), $v } /** - * Marks the script module so it will be exposed in the import map. + * Marks the script module for inclusion in the import map. + * + * Script Modules can rely on the script module dependency graph to include script modules + * in the import map. This method makes it possible to mark a script module for inclusion + * in the import map without relying on the script module dependency graph. * * @since 6.8.0 * * @param string $id The identifier of the script module. */ - public function expose( string $id ) { - $this->exposed[ $id ] = true; + public function include_in_import_map( string $id ) { + $this->marked_for_inclusion[ $id ] = null; } /** @@ -301,7 +309,8 @@ public function print_import_map() { */ private function get_import_map(): array { $imports = array(); - $script_module_ids = array_unique( array_keys( $this->exposed ) + array_keys( $this->get_marked_for_enqueue() ) ); + $script_module_ids = array_unique( array_keys( $this->marked_for_inclusion ) + array_keys( $this->get_marked_for_enqueue() ) ); + foreach ( $this->get_dependencies( $script_module_ids ) as $id => $script_module ) { $src = $this->get_src( $id ); if ( null === $src ) { @@ -309,6 +318,14 @@ private function get_import_map(): array { } $imports[ $id ] = $src; } + foreach ( $this->marked_for_inclusion as $id => $_ ) { + $src = $this->get_src( $id ); + if ( null === $src ) { + continue; + } + $imports[ $id ] = $src; + } + return array( 'imports' => $imports ); } diff --git a/tests/phpunit/tests/script-modules/wpScriptModules.php b/tests/phpunit/tests/script-modules/wpScriptModules.php index 85f9599f0dac3..ce757018631f9 100644 --- a/tests/phpunit/tests/script-modules/wpScriptModules.php +++ b/tests/phpunit/tests/script-modules/wpScriptModules.php @@ -34,7 +34,7 @@ public function set_up() { * * @return array Enqueued script module URLs, keyed by script module identifier. */ - public function get_enqueued_script_modules() { + private function get_enqueued_script_modules() { $script_modules_markup = get_echo( array( $this->script_modules, 'print_enqueued_script_modules' ) ); $p = new WP_HTML_Tag_Processor( $script_modules_markup ); $enqueued_script_modules = array(); @@ -54,10 +54,12 @@ public function get_enqueued_script_modules() { * * @return array Import map entry URLs, keyed by script module identifier. */ - public function get_import_map() { + private function get_import_map() { $import_map_markup = get_echo( array( $this->script_modules, 'print_import_map' ) ); preg_match( '/