Merhaba arkadaşlar, bugün başımı çok ağrıtan bir sorunu ve nasıl temiz bir çözüm bulduğumu anlatacağım. Hepimiz biliyoruz ki modern web'de performans çok kritik, özellikle de görseller konusunda. Geliştirme sırasında sadece bir tane yüksek çözünürlüklü .jpg veya .png dosyası koyup, production'da bunun otomatik olarak optimize edilmiş WebP versiyonlarının ve farklı boyutlar için srcset'lerin oluşmasını istemez miyydik? Ben de çok istedim ve kafayı yemiştim, ta ki bu pipeline'ı kurana kadar.
Karşılaştığım Sorun
Projemde, tasarımcı bana devasa boyutlarda, 4000px genişliğinde görseller atıyordu. Geliştirme ortamında bunları manuel olarak Photoshop'tan geçirip, 5-6 farklı boyuta getirip, sonra da WebP'ye çevirmek tam bir işkenceydi. Üstelik her görsel güncellemesinde bu işlem tekrarlanıyordu. "Bu işin bir otomasyonu olmalı" diye düşünüp yola koyuldum.
Çözüm: Gulp + Sharp İkilisi
Araştırmalarım sonucu, Node.js tabanlı Gulp'ı task runner olarak ve Sharp kütüphanesini de görsel işleme için kullanmaya karar verdim. Sharp, inanılmaz hızlı ve kaliteli sonuçlar veriyor.
İlk olarak projeme bu paketleri yükledim:
Gulpfile.js'in Kalbi
Ana mantık şu: `src/images/original` klasörüme attığım her yüksek çözünürlüklü görseli al, önceden tanımladığım boyutlarda (örneğin 1920, 1280, 768, 480px) yeniden boyutlandır, hem orijinal formatında (.jpg/.png) hem de WebP formatında çıktı al. İşte benim kullandığım en temiz çözümün Gulp task'ı:
HTML'de Kullanım ve srcset Üretimi
Gulp task'ımız `dist/images/optimized` klasörüne `fotoğrafım-1920w.jpg`, `fotoğrafım-1920w.webp`, `fotoğrafım-1280w.jpg`... şeklinde dosyalar üretti. Artık bu dosyaları kullanarak manuel ya da bir template engine ile otomatik `srcset` yazabiliriz. Ben genelde bir component içinde şöyle hallediyorum:
İpuçları ve Dikkat Edilecekler
- Geliştirme ortamında sadece orijinal dosyalarla çalıştığım için `src` klasörüm hafif kalıyor.
- Production build script'ime (`npm run build`) bu `gulp` task'ını ekledim. Böylece `npm run build` dediğimde hem frontend kodum build oluyor hem de tüm görseller otomatik optimize ediliyor.
- Sharp kütüphanesi withoutEnlargement: true parametresi sayesinde orijinalinden daha büyük boyuta çıkarmıyor, bu çok önemli.
- WebP kalitesini (quality) JPEG'den biraz daha düşük tutabilirsiniz, görsel kalitesi neredeyse aynı kalırken dosya boyutu ciddi oranda küçülüyor.
Sonuç olarak, bu pipeline'ı kurduktan sonra hem performans skorlarım yükseldi hem de tasarımcıdan gelen her görsel güncellemesinde içim rahat. Artık tek yapmam gereken büyük dosyayı `original` klasörüne atmak ve `npm run build` demek.
Siz projelerinizde görsel optimizasyon için hangi araçları veya yöntemleri kullanıyorsunuz? Next.js, Vite gibi modern araçlarla entegre etmenin daha pratik bir yolu var mı? Fikirlerinizi merakla bekliyorum!
Projemde, tasarımcı bana devasa boyutlarda, 4000px genişliğinde görseller atıyordu. Geliştirme ortamında bunları manuel olarak Photoshop'tan geçirip, 5-6 farklı boyuta getirip, sonra da WebP'ye çevirmek tam bir işkenceydi. Üstelik her görsel güncellemesinde bu işlem tekrarlanıyordu. "Bu işin bir otomasyonu olmalı" diye düşünüp yola koyuldum.
Araştırmalarım sonucu, Node.js tabanlı Gulp'ı task runner olarak ve Sharp kütüphanesini de görsel işleme için kullanmaya karar verdim. Sharp, inanılmaz hızlı ve kaliteli sonuçlar veriyor.
İlk olarak projeme bu paketleri yükledim:
Bash:
npm install --save-dev gulp gulp-rename sharp gulp-if
Ana mantık şu: `src/images/original` klasörüme attığım her yüksek çözünürlüklü görseli al, önceden tanımladığım boyutlarda (örneğin 1920, 1280, 768, 480px) yeniden boyutlandır, hem orijinal formatında (.jpg/.png) hem de WebP formatında çıktı al. İşte benim kullandığım en temiz çözümün Gulp task'ı:
JavaScript:
const gulp = require('gulp');
const rename = require('gulp-rename');
const sharp = require('sharp');
const path = require('path');
const through2 = require('through2');
// İşlem yapılacak boyutlar (width)
const imageSizes = [1920, 1280, 768, 480];
function processImages() {
return gulp.src('src/images/original//.{jpg,jpeg,png}')
.pipe(through2.obj(async (file, enc, cb) => {
if (file.isBuffer()) {
const originalName = path.basename(file.path, path.extname(file.path));
const originalExt = path.extname(file.path).toLowerCase();
for (const width of imageSizes) {
// Orijinal formatında (JPEG/PNG) işle
try {
const jpgBuffer = await sharp(file.contents)
.resize({ width: width, withoutEnlargement: true })
.jpeg({ quality: 80, mozjpeg: true })
.toBuffer();
const jpgFile = file.clone();
jpgFile.contents = jpgBuffer;
jpgFile.path = path.join(file.base, `${originalName}-${width}w.jpg`);
cb(null, jpgFile);
// AYNI görseli WebP formatında da üret
const webpBuffer = await sharp(file.contents)
.resize({ width: width, withoutEnlargement: true })
.webp({ quality: 75 })
.toBuffer();
const webpFile = file.clone();
webpFile.contents = webpBuffer;
webpFile.path = path.join(file.base, `${originalName}-${width}w.webp`);
cb(null, webpFile);
} catch (err) {
cb(err);
}
}
}
}))
.pipe(gulp.dest('dist/images/optimized'));
}
exports.default = processImages;
Gulp task'ımız `dist/images/optimized` klasörüne `fotoğrafım-1920w.jpg`, `fotoğrafım-1920w.webp`, `fotoğrafım-1280w.jpg`... şeklinde dosyalar üretti. Artık bu dosyaları kullanarak manuel ya da bir template engine ile otomatik `srcset` yazabiliriz. Ben genelde bir component içinde şöyle hallediyorum:
HTML:
<picture>
<!-- WebP versiyonları (öncelikli) -->
<source
type="image/webp"
srcset="
/images/optimized/fotoğrafım-480w.webp 480w,
/images/optimized/fotoğrafım-768w.webp 768w,
/images/optimized/fotoğrafım-1280w.webp 1280w,
/images/optimized/fotoğrafım-1920w.webp 1920w
"
sizes="(max-width: 600px) 480px, (max-width: 900px) 768px, 1280px"
>
<!-- Fallback: Orijinal format (JPEG) -->
<img
src="/images/optimized/fotoğrafım-1280w.jpg"
srcset="
/images/optimized/fotoğrafım-480w.jpg 480w,
/images/optimized/fotoğrafım-768w.jpg 768w,
/images/optimized/fotoğrafım-1280w.jpg 1280w,
/images/optimized/fotoğrafım-1920w.jpg 1920w
"
sizes="(max-width: 600px) 480px, (max-width: 900px) 768px, 1280px"
alt="Açıklayıcı alt metin"
loading="lazy"
>
</picture>
- Geliştirme ortamında sadece orijinal dosyalarla çalıştığım için `src` klasörüm hafif kalıyor.
- Production build script'ime (`npm run build`) bu `gulp` task'ını ekledim. Böylece `npm run build` dediğimde hem frontend kodum build oluyor hem de tüm görseller otomatik optimize ediliyor.
- Sharp kütüphanesi withoutEnlargement: true parametresi sayesinde orijinalinden daha büyük boyuta çıkarmıyor, bu çok önemli.
- WebP kalitesini (quality) JPEG'den biraz daha düşük tutabilirsiniz, görsel kalitesi neredeyse aynı kalırken dosya boyutu ciddi oranda küçülüyor.
Sonuç olarak, bu pipeline'ı kurduktan sonra hem performans skorlarım yükseldi hem de tasarımcıdan gelen her görsel güncellemesinde içim rahat. Artık tek yapmam gereken büyük dosyayı `original` klasörüne atmak ve `npm run build` demek.
Siz projelerinizde görsel optimizasyon için hangi araçları veya yöntemleri kullanıyorsunuz? Next.js, Vite gibi modern araçlarla entegre etmenin daha pratik bir yolu var mı? Fikirlerinizi merakla bekliyorum!