Make WordPress Core

Opened 6 months ago

Closed 3 months ago

Last modified 3 months ago

#64229 closed enhancement (fixed)

Enqueueing scripts, styles, and script modules should warn when dependencies are missing

Reported by: westonruter's profile westonruter Owned by: westonruter's profile westonruter
Milestone: 6.9.1 Priority: normal
Severity: normal Version: 6.9
Component: Script Loader Keywords: has-patch has-unit-tests
Focuses: javascript, performance Cc:

Description (last modified by westonruter)

Given the following plugin code:

<?php
/**
 * Plugin Name: Try in enqueuing classic script and script module with missing dependencies
 */

namespace TryEnqueueingScriptsWithMissingDependencies;

add_action(
        'wp_enqueue_scripts',
        static function () {
                wp_enqueue_script( 'classic-script-with-missing-dependency', 'https://example.com/classic-script.js', array( 'classic-dependency' ) );
                wp_enqueue_script_module( 'script-module-with-missing-dependency', 'https://example.com/script-module.js', array( 'module-dependency' ) );
        }
);

In WordPress 6.8, the classic script is not printed but the script module is. However, as of WordPress 6.9, script modules now behave the same as classic scripts when they have missing dependencies: the script module is not printed. This change was introduced in r60999 to fix #63486. See code in question.

As was extensively troubleshooted in the #core-interactivity-api channel in Slack, this change in behavior was difficult to debug, and it was difficult to identify why a script was not being printed.

Query Monitor actually helpfully warns when attempting to enqueue a classic script script that is missing dependencies, but it doesn't currently do the same for script modules:

https://core.trac.wordpress.org/raw-attachment/ticket/64229/query-monitor.png

This may be due to #60597, where WP_Script_Modules lacks the necessary accessors.

In any case, WordPress core should itself issue a _doing_it_wrong() for both classic scripts and script modules whenever there is a missing dependency for an enqueued script.

Attachments (1)

query-monitor.png (165.9 KB) - added by westonruter 6 months ago.

Download all attachments as: .zip

Change History (36)

#1 @westonruter
6 months ago

  • Description modified (diff)

This ticket was mentioned in PR #10545 on WordPress/wordpress-develop by @deepakprajapati.


6 months ago
#2

  • Keywords has-patch added; needs-patch removed

This PR adds developer-facing _doing_it_wrong() notices when a script or script module is enqueued with dependencies that have not been registered.

Currently, WordPress silently skips printing such assets, which makes dependency issues difficult to diagnose. This change improves debugging clarity during development.

What’s changed
✅ Classic scripts (WP_Scripts)

  • Detects missing dependencies in all_deps().
  • Emits a _doing_it_wrong() notice identifying the script handle and missing dependency handles.

✅ Script modules (WP_Script_Modules)

  • Detects missing dependencies during dependency sorting.
  • Emits a _doing_it_wrong() notice with the module ID and missing dependency IDs.

Both implementations:

  • Prevent duplicate notices using a static cache.

Trac ticket: https://core.trac.wordpress.org/ticket/64229

https://github.com/user-attachments/assets/64a0d617-2b42-4544-b119-d20553f38363

@westonruter commented on PR #10545:


6 months ago
#3

Let's make sure to add unit tests for these changes as well.

#4 @westonruter
6 months ago

  • Keywords needs-unit-tests added

@westonruter commented on PR #10545:


6 months ago
#5

This is looking good to me. I will plan to finish reviewing and commit by next week.

@westonruter commented on PR #10545:


5 months ago
#6

I'm testing this with the following plugin code:

add_action(
        'wp_enqueue_scripts',
        static function () {
                wp_enqueue_script( 'bad-script', '/bad.js', array( 'nope' ) );
                wp_enqueue_style( 'bad-style', '/bad.css', array( 'nope' ) );
                wp_enqueue_script_module( 'bad-module', '/bad.mjs', array( 'nope' ) );
        }
);

I get the following log entries:

  • PHP Notice: Function WP_Dependencies::all_deps was called <strong>incorrectly</strong>. The style with the handle bad-style was enqueued with dependencies that are not registered: nope. Please see <a href="https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/">Debugging in WordPress</a> for more information. (This message was added in version 7.0.0.) in /var/www/src/wp-includes/functions.php on line 6131
  • PHP Notice: Function WP_Dependencies::all_deps was called <strong>incorrectly</strong>. The script with the handle bad-script was enqueued with dependencies that are not registered: nope. Please see <a href="https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/">Debugging in WordPress</a> for more information. (This message was added in version 7.0.0.) in /var/www/src/wp-includes/functions.php on line 6131
  • PHP Notice: Function WP_Script_Modules::sort_item_dependencies was called <strong>incorrectly</strong>. The script module bad-module was enqueued with dependencies that are not registered: nope. Please see <a href="https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/">Debugging in WordPress</a> for more information. (This message was added in version 7.0.0.) in /var/www/src/wp-includes/functions.php on line 6131
  • PHP Notice: Function WP_Script_Modules::sort_item_dependencies was called <strong>incorrectly</strong>. The script module bad-module was enqueued with dependencies that are not registered: nope. Please see <a href="https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/">Debugging in WordPress</a> for more information. (This message was added in version 7.0.0.) in /var/www/src/wp-includes/functions.php on line 6131
  • PHP Notice: Function WP_Script_Modules::sort_item_dependencies was called <strong>incorrectly</strong>. The script module bad-module was enqueued with dependencies that are not registered: nope. Please see <a href="https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/">Debugging in WordPress</a> for more information. (This message was added in version 7.0.0.) in /var/www/src/wp-includes/functions.php on line 6131
  • PHP Notice: Function WP_Dependencies::all_deps was called <strong>incorrectly</strong>. The style with the handle bad-style was enqueued with dependencies that are not registered: nope. Please see <a href="https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/">Debugging in WordPress</a> for more information. (This message was added in version 7.0.0.) in /var/www/src/wp-includes/functions.php on line 6131
  • PHP Notice: Function WP_Dependencies::all_deps was called <strong>incorrectly</strong>. The script with the handle bad-script was enqueued with dependencies that are not registered: nope. Please see <a href="https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/">Debugging in WordPress</a> for more information. (This message was added in version 7.0.0.) in /var/www/src/wp-includes/functions.php on line 6131

The duplication of the notices is indeed not great. I think what I'll do is just add a private member variable to the classes to keep track of what has been flagged with _doing_it_wrong(). This will solve the problem of a static variable not being reset with tests.

What's also confusing is the functions being flagged are unrelated to the functions which may have been called incorrectly by the user. So I think I'll update these to use the WP_Scripts::add(), WP_Styles::add(), and WP_Script_Modules::register() methods which are actually flagged as being called incorrectly. This will make much more sense to a developer.

Also, I'll add quotes around the initial handle ID.

@westonruter commented on PR #10545:


5 months ago
#7

There, I think it is more developer-friendly now. When registering a script, style, and script module with missing dependencies, I now get just three notices:

  1. <b>Notice</b>: Function WP_Styles::add was called <strong>incorrectly</strong>. The style with the handle "bad-style" was enqueued with dependencies that are not registered: nope. Please see <a href="https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/">Debugging in WordPress</a> for more information. (This message was added in version 7.0.0.) in <b>/var/www/src/wp-includes/functions.php</b> on line <b>6131</b><br />
  2. <b>Notice</b>: Function WP_Scripts::add was called <strong>incorrectly</strong>. The script with the handle "bad-script" was enqueued with dependencies that are not registered: nope. Please see <a href="https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/">Debugging in WordPress</a> for more information. (This message was added in version 7.0.0.) in <b>/var/www/src/wp-includes/functions.php</b> on line <b>6131</b><br />
  3. <b>Notice</b>: Function WP_Script_Modules::register was called <strong>incorrectly</strong>. The script module "bad-module" was enqueued with dependencies that are not registered: nope. Please see <a href="https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/">Debugging in WordPress</a> for more information. (This message was added in version 7.0.0.) in <b>/var/www/src/wp-includes/functions.php</b> on line <b>6131</b><br />

@westonruter commented on PR #10545:


5 months ago
#8

Notices as displayed in Query Monitor:

https://github.com/user-attachments/assets/64c6680c-9ed3-423d-bd09-5d4fac43d990

This is in addition to Query Monitor's built-in warnings for scripts and styles (but it doesn't currently warn for missing script module dependencies):

https://github.com/user-attachments/assets/9b6f6073-c35d-43be-8bd4-261d201c7c08
https://github.com/user-attachments/assets/3ee9c905-dccc-439c-ab7a-4595aa9bc654

#9 @westonruter
5 months ago

  • Owner set to westonruter
  • Resolution set to fixed
  • Status changed from new to closed

In 61323:

Script Loader: Emit notices when enqueueing a script, style, or script module with missing dependencies.

Developed in https://github.com/WordPress/wordpress-develop/pull/10545

Follow-up to [60999].

Props deepakprajapati, westonruter.
See #63486.
Fixes #64229.

#10 @westonruter
5 months ago

  • Keywords has-unit-tests added; needs-unit-tests removed
  • Milestone changed from 7.0 to 6.9.1
  • Resolution fixed deleted
  • Status changed from closed to reopened

Given the change in behavior in 6.9 where script modules with missing dependencies are no longer printed, it may be that sites will start breaking where previously they worked in 6.8. This was reported as a big in #64342. Given this, I think we should re-milestone the missing dependency notices for 6.9.1.

The docblocks added in [61323] will need to have their @since tags updated to 6.9.1.

Last edited 5 months ago by westonruter (previous) (diff)

#11 @westonruter
5 months ago

In 61357:

Script Loader: Re-target release for missing dependency notices from 7.0.0 to 6.9.1.

Follow-up to [61323], [60999].

See #64229.

#12 @westonruter
5 months ago

  • Keywords fixed-major added

Commits [61323] and [61357] are ready for review for backporting to 6.9 branch for 6.9.1.

#13 @westonruter
5 months ago

  • Focuses performance added

This ticket was mentioned in Slack in #core-performance by westonruter. View the logs.


5 months ago

#15 @westonruter
5 months ago

  • Summary changed from Enqueueing scripts and script modules should warn when dependencies are missing to Enqueueing scripts, styles, and script modules should warn when dependencies are missing

This ticket was mentioned in Slack in #core by jorbin. View the logs.


4 months ago

#17 @jorbin
4 months ago

  • Keywords dev-feedback added

This ticket was mentioned in PR #10789 on WordPress/wordpress-develop by @jorbin.


4 months ago
#18

PR to test the backport of https://core.trac.wordpress.org/ticket/64229

One merge conflict resolved when running svn merge -c 61323 '^/trunk'

#19 @jorbin
3 months ago

  • Keywords dev-reviewed added; dev-feedback removed

[61323] and [61357] are good for backport.

Note: some flaky tests (logged in #60831) are failing intermittently on the PR.

#20 @wildworks
3 months ago

This is a minor point, but please don't hard-code the comma. The type of separator and whether or not there's a space after the separator may differ depending on the locale.

I think we'll need to use the wp_get_list_item_separator() function.

Recommended code example:

protected function get_dependency_warning_message( $handle, $missing_dependency_handles ) {
        $comma = wp_get_list_item_separator();
        return sprintf(
                /* translators: 1: Script handle, 2: List of missing dependency handles. */
                __( 'The script with the handle "%1$s" was enqueued with dependencies that are not registered: %2$s.' ),
                $handle,
                implode( $comma, $missing_dependency_handles )
        );
}

This ticket was mentioned in Slack in #core by wildworks. View the logs.


3 months ago

@wildworks commented on PR #10799:


3 months ago
#23

### How to test this PR

Switch the site locale to Japanese and enqueue a script with a non-existent dependency in an active theme. Example:

  • src/wp-content/themes/twentytwentyfive/functions.php

    diff --git a/src/wp-content/themes/twentytwentyfive/functions.php b/src/wp-content/themes/twentytwentyfive/functions.php
    index 8e4acf1e35..b30bdd93a5 100644
    a b if ( ! function_exists( 'twentytwentyfive_format_binding' ) ) : 
    157157               }
    158158       }
    159159endif;
     160
     161add_action( 'wp_enqueue_scripts', function () {
     162       wp_register_script(
     163               'test-missing-deps',
     164               includes_url( 'js/wp-embed.min.js' ),
     165               array( 'non-existent-dependency-1', 'non-existent-dependency-2', 'non-existent-dependency-3' ),
     166               null,
     167               true
     168       );
     169       wp_enqueue_script( 'test-missing-deps' );
     170} );

Then, open http://localhost:8889/

Make sure the separator is and not , . This character is a separator used in Japanese.

https://github.com/user-attachments/assets/4c4a7f4e-f665-417f-8a86-d7e5756d64f2

@mukesh27 commented on PR #10799:


3 months ago
#24

Did some quick review and found same error for https://github.com/WordPress/wordpress-develop/pull/10799#issuecomment-3804272398 diff code.

Function WP_Scripts::add was called incorrectly. The script with the handle "test-missing-deps" was enqueued with dependencies that are not registered: non-existent-dependency-1、non-existent-dependency-2、non-existent-dependency-3. (This message was added in version 6.9.1.)

This ticket was mentioned in Slack in #core-performance by mukeshpanchal27. View the logs.


3 months ago

This ticket was mentioned in Slack in #core by jorbin. View the logs.


3 months ago

#27 @jorbin
3 months ago

  • Keywords commit added; fixed-major dev-reviewed removed

Updating tags based on the need for a follow up commit. https://github.com/WordPress/wordpress-develop/pull/10799 looks good for trunk.

#28 @wildworks
3 months ago

In 61542:

Script Loader: Use localized list separators in dependency warning messages.

Improve dependency warning messages so that list separators are localized according to the current locale when multiple dependencies are listed.

Follow-up to [61323], [60999], [61357].

Props mukeshpanchal27, jorbin, westonruter, wildworks.
See #64229.

#30 @wildworks
3 months ago

  • Keywords commit removed

#32 @wildworks
3 months ago

I committed [61542] myself, but backporting [61323], [61357], and [61542] to 6.9 looks good to me.

#33 @jorbin
3 months ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In 61550:

Script Loader: Emit notices when enqueueing a script, style, or script module with missing dependencies.

First Developed in https://github.com/WordPress/wordpress-develop/pull/10545. Backport developed in https://github.com/WordPress/wordpress-develop/pull/10789.

Follow-up to [60999].

Reviewed by jorbin, wildworks.
Merges [61323], [61357], and [61542].

Props deepakprajapati, westonruter, mukeshpanchal27, jorbin, wildworks.
See #63486.
Fixes #64229.

#35 @westonruter
3 months ago

In 61587:

Script Loader: Allow classic scripts to depend on script modules.

This allows classic scripts to declare dependencies on script modules by passing module_dependencies in the $args param for wp_register_script() or wp_enqueue_script(). The WP_Script_Modules::get_import_map() method is updated to traverse the dependency tree of all enqueued classic scripts to find any associated script module dependencies and include them in the importmap, enabling dynamic imports of modules within classic scripts.

A _wp_scripts_add_args_data() helper function is introduced to consolidate argument validation and processing for wp_register_script() and wp_enqueue_script(), reducing code duplication. This function validates that the $args array only contains recognized keys (strategy, in_footer, fetchpriority, module_dependencies) and triggers a _doing_it_wrong() notice for any unrecognized keys. Similarly, WP_Scripts::add_data() is updated to do early type checking for the data passed to $args. The script modules in module_dependencies may be referenced by a module ID string or by an array that has an id key, following the same pattern as dependencies in WP_Script_Modules.

When a script module is added to the module_dependencies for a classic script, but it does not exist at the time the importmap is printed, a _doing_it_wrong() notice is emitted.

Developed in https://github.com/WordPress/wordpress-develop/pull/8024

Follow-up to [61323].

Props sirreal, westonruter.
See #64229.
Fixes #61500.

Note: See TracTickets for help on using tickets.