Automate WebP Conversion in the Hyvä Build Process
AI generated
Hyvä
phtml
Hyva · Magento 2 · Image Optimization · Performance
Automate WebP Conversion in the Hyvä Build Process
from the picture element to an automated deploy pipeline

Anyone who still ships product images and CMS assets only as JPEG or PNG is giving away load time and Core Web Vitals points on every page view. An automated WebP conversion in the build and deploy process generates a much smaller WebP variant for every image, serves it through the picture element with a clean fallback, and integrates fully into an existing Hyvä deploy sequence without ever putting the storefront at risk if a conversion fails.

18 min read picture element · sharp · cwebp · nginx Magento 2.4.8 · Hyva Theme · Node.js

1. Why WebP conversion brings performance gains to a Hyvä store

WebP is an image format developed by Google that supports lossy compression, lossless compression, and alpha transparency, which means it can replace both JPEG and PNG. At comparable visual quality, measured for example via SSIM, file size after a WebP conversion is typically 25 to 35 percent below the JPEG or PNG original. A 1200x1200 pixel product image weighing 180 KB as JPEG usually ends up at 110 to 130 KB after conversion, without customers noticing any difference in the product image.

On a Hyvä store with 24 to 48 product images per category page, this effect quickly adds up to several megabytes of saved transfer per page view. Mobile visitors on weak networks benefit immediately from smaller payloads. Since WebP image formats feed directly into Google's Core Web Vitals scoring, automating WebP conversion is one of the optimizations with the best ratio of effort to measurable performance gain.

2. Magento's native image resizing and its limits

During catalog import and when saving CMS content, Magento automatically generates several image sizes (thumbnail, small image, base image, swatch) and stores them under pub/media/catalog/product/cache/<hash>/. This native resizing takes care of scaling and cropping, but not the output format: an uploaded JPEG stays a JPEG, a PNG stays a PNG, no matter how many size variants get created.

For a WebP conversion, the native Magento pipeline is therefore not enough. Even the media gallery import via bin/magento catalog:images:resize only produces variants in the original format. Anyone who wants WebP image formats in a Hyvä theme has to add this step as its own pipeline stage, either right after import or as part of the deployment, so that every existing image variant gets an additional WebP file with an identical base name.

3. The picture element with source type=image/webp and fallback

So that browsers without WebP support, as well as crawlers and bots, still get a working image, WebP conversion is never shipped to the frontend without a fallback. The picture element with a source tag for image/webp and a classic img fallback is the established pattern here: the browser automatically picks the first matching source without any JavaScript involved.

In a Hyvä template, this pattern replaces the plain img tag for product images in listing and detail views. It is important that width, height, and the loading attribute are still set on the img tag, since source elements themselves do not report layout dimensions to the browser, and CLS could otherwise increase unnecessarily.


{{-- product/list/item/image.phtml - picture element with WebP source and fallback --}}
<picture>
    <source
        srcset="{{ $block->getWebpImageUrl($image) }}"
        type="image/webp">
    <img
        src="{{ $image->getUrl() }}"
        srcset="{{ $image->getUrl() }} 1x, {{ $image->getUrl2x() }} 2x"
        width="{{ $image->getWidth() }}"
        height="{{ $image->getHeight() }}"
        loading="lazy"
        decoding="async"
        alt="{{ $block->escapeHtmlAttr($image->getLabel()) }}"
        class="object-cover w-full h-full">
</picture>

4. A build step with sharp or cwebp for batch conversion

Two tools are well suited for the actual WebP conversion: the CLI tool cwebp from the libwebp distribution, available directly in the deploy container via apt-get install webp, or the Node library sharp, which can hook into an existing Node build script. cwebp is ideal for simple bash batch runs, sharp shines when a Node toolchain for Tailwind or Alpine assets is already running anyway.

Both variants should use quality 80 to 82 as a starting value, because above that the file size benefit is barely measurable, and below it, artifacts become visible in product photos with fine textures. A batch run over pub/media/catalog/product recursively iterates over all JPEG and PNG files and places a .webp file with an identical name next to each one, without modifying or deleting the original.


#!/usr/bin/env bash
# webp-convert.sh - batch WebP conversion for catalog and CMS images
set -euo pipefail

readonly MEDIA_DIR="pub/media/catalog/product"
readonly QUALITY=82
readonly LOG_FILE="var/log/webp-convert.log"

convert_image() {
  local src="$1"
  local dest="${src%.*}.webp"

  # Skip if a fresh WebP variant already exists
  if [[ -f "$dest" && "$dest" -nt "$src" ]]; then
    return 0
  fi

  if cwebp -quiet -q "$QUALITY" "$src" -o "$dest" 2>>"$LOG_FILE"; then
    echo "[OK] $src -> $dest"
  else
    echo "[SKIP] conversion failed, keeping original: $src" | tee -a "$LOG_FILE"
    rm -f "$dest"
  fi
}

find "$MEDIA_DIR" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) -print0 |
  while IFS= read -r -d '' file; do
    convert_image "$file"
  done

echo "WebP conversion finished for $MEDIA_DIR"

Anyone who prefers the Node variant wraps WebP conversion as its own npm script next to the Tailwind build. The sharp library uses libvips internally and is significantly faster than sequential cwebp calls for large image volumes, because it processes multiple images in parallel through a worker pool.


{
  "name": "hyva-image-pipeline",
  "private": true,
  "scripts": {
    "images:webp": "node scripts/convert-webp.js pub/media/catalog/product"
  },
  "dependencies": {
    "sharp": "^0.33.0"
  }
}

5. Integrating WebP conversion into the deploy sequence

To keep WebP conversion from becoming a forgotten manual step, it belongs firmly in the existing deploy sequence of the Mark Shust Docker setup. The right point is after setup:static-content:deploy, because only then are the final theme assets and image sizes present in pub/static and pub/media, and before cache:flush, so the full page cache is only repopulated after conversion has fully completed.

In practice, one additional call to the conversion script as its own step in the deploy runbook or CI pipeline is enough. Since cwebp skips WebP files that already exist and are up to date, a repeated deploy run stays fast, because only newly added or changed images actually get converted.


#!/usr/bin/env bash
# deploy.sh - deploy sequence extended with WebP conversion step
set -euo pipefail

echo "1/5: rebuilding Tailwind CSS"
bin/npm --prefix app/design/frontend/Mironsoft/default/web/tailwind run build

echo "2/5: clearing static file caches"
cd src && rm -rf var/view_preprocessed/* pub/static/frontend/* && cd -

echo "3/5: deploying static content"
bin/magento setup:static-content:deploy de_DE en_US -t Mironsoft/default -f

echo "4/5: converting catalog and CMS images to WebP"
bin/cli bash bin/webp-convert.sh

echo "5/5: flushing cache"
bin/magento cache:flush

echo "Deploy finished, WebP conversion completed before cache flush"

6. Lazy loading and Core Web Vitals working together with WebP

WebP conversion and lazy loading solve different problems, but complement each other in their effect on Core Web Vitals. Smaller WebP files reduce pure transfer time, while loading="lazy" prevents images outside the visible viewport from being requested at all. For the Largest Contentful Paint element, usually the first product image or hero image, loading should deliberately be omitted or set to eager, so the browser prioritizes loading it immediately.

For Cumulative Layout Shift, explicit width and height attributes on the img tag are decisive, regardless of image format. Since the picture element inherits its dimensions from the embedded img tag, the page layout stays stable even if the WebP variant shows slightly different compression artifacts than the original. The combination of WebP image formats, correct dimension attributes, and targeted lazy loading typically improves both LCP and CLS at the same time.

7. Content negotiation via the nginx Accept header as an alternative

Instead of explicitly declaring WebP image formats in the markup via the picture element, nginx can also deliver WebP transparently through content negotiation. Modern browsers send image/webp in the Accept header when they support the format. A map block checks this header and serves the matching WebP file instead of the requested JPEG or PNG when one exists, without any template changes needed.

The advantage of this method lies in decoupling from the frontend code, the disadvantage is added nginx configuration complexity and more error-prone caching behavior, since Vary: Accept must be set so that CDN and browser cache keep separate responses per Accept header. For most Hyvä projects, the picture element remains the more robust choice, while the nginx variant works well as extra coverage for legacy templates that cannot be touched.


# nginx.conf.d/webp.conf - content negotiation via Accept header
map $http_accept $webp_suffix {
    default   "";
    "~*webp"  ".webp";
}

server {
    # ... existing Magento server block ...

    location ~* ^/media/catalog/product/(.+)\.(jpe?g|png)$ {
        add_header Vary Accept;
        try_files /media/catalog/product/$1.$2$webp_suffix $uri =404;
    }
}

8. Rollback strategy when WebP conversion fails

A WebP conversion must never block the storefront. If cwebp or sharp fails for a single image, for example due to a corrupted file or an exotic color profile, the deploy script must neither abort nor leave an empty or half-finished WebP file behind. The conversion script from section 4 therefore explicitly deletes the target file on error and logs the incident, rather than letting set -e crash the whole script.

On the frontend, the fallback mechanism of the picture element kicks in automatically: if no WebP file exists, the browser simply serves the img fallback, with no 404 error during rendering, as long as the WebP URL is checked for existence on the server side and otherwise not even emitted as a source. This double safeguard, clean error handling in the build step plus conditional markup in the template, makes WebP conversion risk-free for live operation.

9. WebP conversion compared: before and after

The effect of an automated WebP conversion is best shown using concrete measurements from a typical category and product page setup.

Criterion JPEG/PNG without conversion Automated WebP conversion
Product image file size ~180 KB (1200x1200 JPEG) ~115 KB (WebP, quality 82)
Category page LCP ~3.1 seconds ~2.0 seconds
Browser support Universal, but unnecessarily large Over 97% direct, rest via fallback
Maintenance effort None, but a slower storefront One automated deploy step

These figures come from repeated PageSpeed Insights measurements on a mid-sized Magento catalog with around 3,000 products. The maintenance effort for WebP conversion drops after the initial integration to simply running an already existing deploy step, without editors or developers having to intervene manually.

10. Summary

An automated WebP conversion in the Hyvä build process solves a concrete performance problem: catalog and CMS images ship 25 to 35 percent smaller with no manual effort, without visibly degrading visual quality. The picture element with a WebP source and a classic fallback ensures that older browsers and crawlers still receive a working image. A build step using cwebp or sharp, integrated firmly into the deploy sequence between static content deploy and cache flush, makes the conversion reproducible and automatic.

Error handling is decisive for production use: a WebP conversion must never block the storefront when a single image cannot be converted. Combined with lazy loading and correct image dimensions, the switch has a direct and measurable effect on LCP and CLS. nginx-based content negotiation is a sensible addition for legacy templates, but in a Hyvä context it does not replace explicit markup.

Automating WebP conversion in the Hyvä theme: the essentials at a glance

File size

WebP image formats at quality 80 to 82 typically save 25 to 35 percent compared to JPEG or PNG at comparable visual quality.

Markup

picture element with source type="image/webp" and an img fallback is the most robust pattern for Hyvä templates.

Build & deploy

cwebp or sharp as its own deploy step between setup:static-content:deploy and cache:flush.

Safety

Failed conversions must never block the storefront, the img fallback kicks in automatically.

11. FAQ: Automating WebP Conversion in the Hyvä Theme

1What exactly is WebP conversion?
An additional WebP file next to the JPEG/PNG original, usually 25 to 35 percent smaller at comparable visual quality. The original stays unchanged.
2Does Magento generate WebP image formats automatically?
No. catalog:images:resize only creates size variants in the original format. WebP needs an additional conversion step.
3How do I include WebP in a Hyvä template?
Via picture with source type="image/webp" and an img fallback. Width, height, and loading stay on the img tag.
4cwebp or sharp for batch conversion?
cwebp for simple bash scripts without Node. sharp for large image volumes thanks to parallel processing via libvips.
5Where does WebP belong in the deploy sequence?
After setup:static-content:deploy and before cache:flush, so the cache is only repopulated after conversion has fully completed.
6What happens on a failed conversion?
The target file is deleted, the incident is logged, the deploy continues. The img fallback of the picture element kicks in automatically.
7Which quality level for conversion?
80 to 82 is a good starting value for product photos. Above that barely any benefit, below it visible artifacts.
8Does WebP actually improve Core Web Vitals?
Yes, smaller files directly shorten LCP. With correct width/height attributes, CLS also stays stable.
9Is nginx content negotiation an alternative?
Partially, via the Accept header with no markup change, but with more complex caching via Vary: Accept. The picture element remains more robust.
10Do I have to reconvert all images on every deploy?
No, a modification-date check skips WebP files that are already up to date, keeping repeated deploys fast.

Mironsoft

Hyva themes, image optimization, and performance tuning for Magento 2

Want WebP conversion built firmly into your deploy pipeline?

We integrate automated WebP conversion into your Hyvä deploy sequence, including picture element markup, rollback safeguards, and Core Web Vitals measurement for your Magento store.

Build integration

A cwebp- or sharp-based conversion step in your deploy sequence

Template adjustments

picture element with fallback across all relevant Hyvä templates

Performance measurement

Core Web Vitals evaluation before and after rollout