Opened 17 months ago
Last modified 8 weeks ago
#62709 new enhancement
Script modules integration with wp_resource_hints
| Reported by: |
|
Owned by: | |
|---|---|---|---|
| Milestone: | 7.1 | Priority: | normal |
| Severity: | minor | Version: | 6.5 |
| Component: | Script Loader | Keywords: | has-patch has-unit-tests |
| Focuses: | javascript, performance | Cc: |
Description
The wp_dependencies_unique_hosts() function returns a list of all the unique hosts that appear in script and style dependencies.
That data is used by the wp_resource_hints() function to print DNS <link rel="dns-prefetch" href="{{ HOST_NAME }}"> tags, a performance hint used by browsers.
wp_dependencies_unique_hosts does not inspect script modules at all. The result is that performance hints are not printed for script modules.
Script modules do handle some of their own performance hints, in particular rel=modulepreload link tags are printed via WP_Script_Modules::print_script_module_preloads(), but script modules miss out on this broader handling of dependencies via wp_resource_hints for dns-prefetch.
This is likely blocked on #60597, it requires exposing information about script modules for inspection.
Change History (8)
#2
@
17 months ago
- Severity changed from normal to minor
modulepreload is only added for static module dependencies.
Modules dependencies like the following will not have a modulepreload added (assuming it's not a static import anywhere else in the dependency graph):
$deps = array(
array( 'id' => 'my-module', 'import' => 'dynamic' ),
);
Dynamic dependencies would still benefit from dns-prefetch.
These dns-prefetches are also added early to the page. On non-block themes, all of the script module tags are printed in the footer so there may also be an opportunity for dns-prefetch to happen before any of the module related tags are processed.
This ticket was mentioned in Slack in #core-performance by westonruter. View the logs.
3 months ago
#7
@
2 months ago
Thanks for filing this — the gap is clear. Here are some thoughts on a possible approach.
The Core Issue
wp_dependencies_unique_hosts() currently only loops over $wp_scripts and $wp_styles:
foreach ( array( $wp_scripts, $wp_styles ) as $dependencies ) {
// ...
}
WP_Script_Modules is a completely separate system and is never consulted, so no dns-prefetch hints are emitted for external hosts used by script modules.
Possible Approaches
Option A: Hook into wp_resource_hints filter from within WP_Script_Modules
One approach could be to add a new public method to WP_Script_Modules — something like filter_resource_hints( array $urls, string $relation_type ): array — and register it from within add_hooks():
add_filter( 'wp_resource_hints', array( $this, 'filter_resource_hints' ), 10, 2 );
The method would:
- Only act when
$relation_type === 'dns-prefetch' - Walk the queue and all dependencies (both static and dynamic)
- Parse the host from each
srcURL, filtering out same-site hosts - Merge the resulting hosts into
$urlsand return
This keeps all the logic inside WP_Script_Modules and avoids changing the signature or behavior of wp_dependencies_unique_hosts().
Option B: Extend wp_dependencies_unique_hosts() directly
Alternatively, wp_dependencies_unique_hosts() could be extended to also inspect $wp_script_modules. This would require exposing a getter on WP_Script_Modules (e.g. get_registered_srcs() or similar), which may partly overlap with the work in #60597.
A Note on Redundancy
As @swissspidy raised — print_script_module_preloads() already emits rel="modulepreload" for static dependencies, and modulepreload implies a full connection (DNS + TCP + TLS). Adding dns-prefetch on top of those may be redundant.
That said, two cases still seem clearly worth targeting:
- Dynamic dependencies — declared as
'import' => 'dynamic', these are never preloaded and currently receive no performance hint at all. - Classic themes —
wp_resource_hintsfires inwp_headat priority 2, while all module-related tags fire inwp_footeron classic themes. Even for static deps, an earlydns-prefetchin the head could give the browser a head start before any module tag is encountered.
Option A could optionally be scoped to only emit dns-prefetch for dynamic-dependency hosts (skipping those already covered by modulepreload), though that could also be left as a follow-up to keep the initial patch simpler.
Tests
Any patch would likely need companion PHPUnit tests, probably alongside tests/phpunit/tests/general/wpResourceHints.php, covering:
- Dynamic-dependency hosts appear in dns-prefetch
- Static-dependency hosts (already covered by modulepreload) are either included or explicitly excluded, depending on the chosen design
- Same-site hosts are not included
Happy to help put together a patch if this direction looks reasonable.
This ticket was mentioned in PR #11374 on WordPress/wordpress-develop by @sanket.parmar.
8 weeks ago
#8
- Keywords has-patch has-unit-tests added; needs-patch removed
## Description
`wp_resource_hints()` prints <link rel="dns-prefetch"> tags for all external hosts used by enqueued scripts and styles, giving browsers an early signal to resolve DNS before requests are made. However, WP_Script_Modules was never wired into this system, so external hosts referenced by script modules received no DNS prefetch hints.
This PR addresses #62709 by adding a new public method WP_Script_Modules::filter_resource_hints(), registered on the wp_resource_hints filter inside add_hooks(). The method collects all enqueued module IDs and their full dependency tree — including dynamic dependencies, which never receive modulepreload hints and are therefore the clearest gap — parses each src for its host, filters out same-site hosts, and appends the external URLs to the dns-prefetch hints array. Deduplication by host is handled downstream by wp_resource_hints() itself, as it does for scripts and styles.
On classic themes, wp_resource_hints fires in wp_head at priority 2, while all module-related tags fire in wp_footer. This means even static dependency hosts will benefit from an early hint in the page <head> well before any module tag is processed.
## Changes
src/wp-includes/class-wp-script-modules.php- Added
filter_resource_hints( array $urls, string $relation_type ): arraypublic method. - Registered the filter in
add_hooks()viawp_resource_hints.
- Added
tests/phpunit/tests/script-modules/wpScriptModulesResourceHints.php_(new file)_- 9 tests covering: enqueued modules, static dependencies, dynamic dependencies, same-site exclusion, relative-path exclusion, registered-only exclusion, non-dns-prefetch relation types left unmodified, host deduplication, and full
wp_resource_hints()integration.
- 9 tests covering: enqueued modules, static dependencies, dynamic dependencies, same-site exclusion, relative-path exclusion, registered-only exclusion, non-dns-prefetch relation types left unmodified, host deduplication, and full
## How to test
- Enqueue a script module with an external
src, e.g.:`php wp_enqueue_script_module( 'my-module', 'https://cdn.example.com/module.js' );
---
Trac ticket: https://core.trac.wordpress.org/ticket/62709
## Use of AI Tools
To clarify, you want to add
dns-prefetchfor script modules in addition tomodulepreload? If you already preload there is no need to prefetch though.