Problem/Motivation
When the webp module is enabled alongside Responsive Image Preload, the rendered <picture> element serves WebP derivatives (via webp_preprocess_responsive_image()), but the preload <link rel="preload" as="image"> tags generated by this module still point at the original PNG/JPEG URLs from ImageStyle::buildUrl().
That mismatch defeats the purpose of preloading for LCP: the browser may preload a format it will not use, while the actual LCP candidate is a WebP URL the preload hints never mention.
Example (observed on a Drupal 11.4.4 site with both modules enabled):
<picture>sources:.../style/foo.webp?itok=...withtype="image/webp"- Preload links:
.../style/foo.png?itok=...(notype="image/webp")
Related issue (mistakenly closed for 2.0.x)
This was reported previously in #3229962: Supports webp module. That issue was marked Fixed in 2021 with reference to #3232744, which addressed the 1.x codebase. The problem was reopened in May 2025 for 2.0.x-dev because responsive_image_preload 2.0.x was refactored and does not include WebP handling in PreloadGenerator. As of 2.0.1, preloads still emit non-WebP URLs when webp is enabled.
Steps to reproduce
- Enable
responsive_image_preloadandwebp. - Configure a responsive image field with
generate_preloads: trueon its formatter settings. - View a page that renders a responsive hero (or any) image.
- Inspect HTML: compare
<picture><source type="image/webp">URLs with<link rel="preload" as="image">imagesrcsetvalues. - Expected: Preload URLs match the WebP URLs the browser will fetch (with
type="image/webp"on the preload link). - Actual: Preload URLs remain
.png/.jpg/.jpegwhile the picture element prefers WebP.
Environment tested: Drupal 11.4.4, PHP 8.3, responsive_image_preload 2.0.1, webp 1.x.
Proposed resolution
When the webp module is present:
- Optionally inject the
webp.webpservice intoPreloadGenerator(e.g.@?webp.webpinresponsive_image_preload.services.yml). - After building
imagesrcset, convert URLs withWebp::getWebpSrcset()— the same helperwebpuses when altering responsive images — so preload URLs stay in sync with<picture>output (including preserved?itok=tokens). - Add
type="image/webp"on preload<link>elements. - Emit WebP-only preloads when WebP is available (do not also preload PNG/JPEG duplicates the browser will not use for LCP).
When webp is not installed, behavior should remain unchanged (backward compatible).
Credits and prior work
Thank you to everyone who already investigated this on #3229962:
- ahmad smhan — original report and early patches
- luke.leber — follow-up ensuring
?itok=is preserved in WebP URLs - nicodh — May 2025 patches for 2.0.x, including the approach of skipping JPG/PNG preloads when WebP is present (comment #14)
Thanks also to joncjordan for discovering that the previously reported issue had been mistakenly closed and that WebP images were still not getting preloaded.
This merge request is informed by that thread rather than reinventing the problem. I chose a new, smaller patch for 2.0.x because:
- 2.0.x API:
PreloadGeneratorwas rewritten; 1.x / early patches do not apply cleanly to 2.0.1. - DRY with
webp: Instead of duplicatingpreg_replace()logic, callwebp.webp→getWebpSrcset()so preload URLs always match whatwebp_preprocess_responsive_image()produces. - Optional dependency:
@?webp.webpkeeps a soft dependency onwebp(no hard module requirement; no\Drupal::static service calls in the generator). - LCP-focused behavior: Same intent as nicodh’s “without jpg/png preload if webp is present” variant — avoid double-downloading formats the browser will not use.
Remaining tasks
- [x] Confirm reproduction on 2.0.x with
webpenabled - [ ] Review merge request against
2.0.x - [ ] Consider automated/kernel test coverage if feasible
- [ ] Merge and tag a release
User interface changes
None. Markup change only: preload <link> tags use WebP URLs and type="image/webp" when the webp module is enabled.
API changes
None for public APIs. PreloadGenerator constructor gains an optional $webp argument (injected via @?webp.webp).
Data model changes
None.
| Comment | File | Size | Author |
|---|---|---|---|
| responsive_image_preload-supports-webp.patch | 2.68 KB | btully |
Issue fork responsive_image_preload-3622332
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
btully commentedMerge request: https://git.drupalcode.org/project/responsive_image_preload/-/merge_requ...
Ready for review. Patch also attached in the initial report if helpful.
Comment #4
btully commented