rosell-dk/webp-convert
PHP library for converting JPEG, PNG and other images to WebP. It tries multiple converters (cwebp, vips, Imagick, GD, ffmpeg, cloud APIs) with automatic fallback, so conversions succeed even on limited hosts. Includes quality options, error handling and framework integrations.
Architecture fit. rosell-dk/webp-convert is a self-contained library, not a service or framework plugin. It exposes a small procedural surface (WebPConvert::convert(), Converters::getConvertersInstalled(), per-converter options) that takes a source path, a destination path, and an options array. That makes it a clean fit for a Laravel media pipeline as a leaf dependency behind an internal adapter — nothing about it wants to own your storage layer, your queue, or your HTTP responses. The architectural decision to isolate is important: the library's core value proposition is that it tries multiple backends in order (cwebp binary, vips, Imagick, GD, ffmpeg, GraphicsMagick, and cloud fallbacks). That polyglot backend model is both its strength and the main thing you want to encapsulate, because it means runtime behavior varies by host.
Integration feasibility. High. Composer install, PSR-4 autoloading, MIT license, no service dependency, no credentials required for the local backends. A competent Laravel developer can have a working converter in an afternoon. The friction points are environmental rather than code-level: the binary backends shell out, so exec/proc_open/shell_exec must be available, and the extension backends require PHP built with WebP support (GD imagewebp) or ImageMagick compiled with a WebP delegate. On managed/shared hosting, one or more of these will be unavailable — which the library handles gracefully by falling through, but silently unless you instrument it.
Technical risk.
Storage disks. S3/object-storage deployments require a download-to-temp → convert → upload round trip, which adds latency and temp-disk pressure.memory_limit or max_execution_time if called inline in a request.Key questions for the team.
Accept-header negotiation?Stack fit. Laravel-native in all the ways that matter: Composer, PSR-4, no global state, no facade requirement, exception-based error handling the framework can catch. It does not conflict with intervention/image or spatie/image — but you should not run both for the same concern. If the team already standardizes on Intervention for resizing, the pragmatic split is Intervention for geometry and webp-convert for the encode step, since the latter's backend fallback is materially better than Intervention's "whatever GD/Imagick gives you."
Migration path. There is no migration in the schema sense; the migration is organizational. For an existing media library, plan a backfill: an idempotent job that walks existing assets, converts, writes the derivative, and records the source hash + options + backend used so re-runs are no-ops. Keep original uploads untouched — WebP derivatives are additive artifacts, which makes rollback a matter of deleting a directory rather than restoring a backup.
Compatibility. Verify the PHP constraint against your runtime matrix (the project has historically supported older PHP than most current Laravel versions require, so the constraint is unlikely to be the blocker). Confirm GD/Imagick WebP support and binary availability in each environment via a startup health check rather than discovering it in production. Pin to a minor version and treat upgrades as scheduled work, given single-maintainer upstream.
Sequencing.
Converters::getConvertersInstalled() and record the output.ImageEncoder interface with one implementation. Nothing else in the codebase imports the package directly.timeout and memory_limit; cap input dimensions and short-circuit oversized/corrupt files.hash(source, encoder_version, backend, quality, format). This is where the actual engineering effort lives — not in the library.Maintenance. Low code-churn, low surface area, MIT. The maintenance burden is dominated by environment drift — base image upgrades that drop a binary, PHP minor versions that change extension compilation — not by the package itself. Budget a recurring check in the deploy pipeline that asserts backend availability and fails the build if the expected backend disappears.
Support. Upstream responsiveness is the main unknown; the fork-and-patch escape hatch is genuinely viable at this size (~600 stars, focused scope, permissive license). Internally, the support story is good if you instrument early: log which converter was selected, conversion duration, input and output byte counts, and the failure reason. Without that, "images are slow" and "images are broken" are indistinguishable.
Scaling. Conversion is CPU-bound and roughly linear in pixel count. Throughput scales with worker count, not with web nodes, so size the queue pool from measured p95 (expect hundreds of milliseconds per typical photographic image with cwebp; GD is slower and lower quality). Watch temp-disk consumption for the object-storage path and set concurrency limits to stay under it. Caching is the real scaling lever: a high cache-hit ratio turns this from a per-request cost into a one-time cost per asset per variant.
Failure modes to design for.
file_exists.Ramp-up. Low for the library, moderate for the pipeline. A Laravel developer with no image-processing background can be productive with the API in under a day; the nontrivial knowledge is the surrounding context — which backend each environment has, why quality settings are what they are, how the cache key is composed, and what the fallback is when WebP isn't served. Document those four things in the repo and the ongoing cognitive load is minimal. Given the 603 stars, active release cadence, MIT license, and narrow scope, this is a buy/adopt-with-wrapper call rather than a build — but only after confirming that an edge/CDN transform isn't already available in the stack, which would make the entire runtime component unnecessary.
How can I help you explore Laravel packages today?