Bu yazıda React + Vite projelerinde bundle size’ınızı nasıl inceleyeceğinizi, hangi araçların hangi işe yaradığını ve isterseniz hazır paketlerle, isterseniz kendi çözümünüzle CI/CD’ye nasıl entegre edeceğinizi ele alacağız.
🔍 Bundle Analyzer Nedir?
Bundle Analyzer, production build’inizden çıkan JavaScript dosyalarının içinde ne olduğunu görsel olarak gösteren bir araçtır. Genelde treemap adı verilen hiyerarşik bir diyagram çizer: Her modül bir dikdörtgen olur, dikdörtgenin alanı modülün bundle içindeki boyutuyla orantılıdır.
Yani dist/ klasöründe gördüğünüz 800KB'lık index-abc123.js dosyasının içini açıp, "hangi kütüphane ne kadar yer kaplıyor?" sorusuna net cevap alabileceğiniz bir röntgen cihazı gibi düşünebiliriz 😁
Bundle analyzer’dan çıkan temel bilgiler:
★ Stat size — Minify edilmemiş orijinal boyut
★ Parsed size — Rollup’ın raporladığı boyut; Vite minification’ı varsayılan olarak etkinleştirdiğinden bu değer gerçek boyuttan büyük görünebilir
★ Gzipped size — Gzip sıkıştırması sonrası boyut (yani kullanıcının gerçekte indirdiği boyut)
★ Module graph — Hangi modül hangi paketten geliyor
★ Duplicate detection — Aynı paketin farklı versiyonlarının varlığı
📊 Neden Bundle Size’ı Ölçmeliyiz?
En basit tabirle, ölçemediğiniz şeyi iyileştiremeyiz 😅
Chrome DevTools’un Network sekmesinde bir main.js dosyasının 1.2MB olduğunu görmek size hiçbir şey ifade etmez. O 1.2MB'ın 400KB'ı gerçekten ihtiyaç duyduğunuz kodsa, optimize edecek bir şey yoktur. Ama o 1.2MB'ın 300KB'ı yanlışlıkla import ettiğiniz bir kütüphane veya tree-shake edilememiş bir paketse, o 300KB'ı kurtarabiliriz.
Bundle analyzer olmadan bu ayrımı yapmamız oldukça zor. Tahmin yürütebiliriz, “şu kütüphaneyi değiştirsek acaba?”, değiştiririz, Network sekmesine bakabiliriz. Ancak bu biraz yorucu bir süreç
Bundle analyzer ile şu soruların cevabını net olarak alabiliriz:
★ Hangi paketler bundle’da en çok yer kaplıyor?
★ Duplicate paket var mı? (Aynı kütüphanenin farklı sürümleri)
★ Yeni eklediğim dependency bundle’a ne ekledi?
★ Tree-shaking çalışıyor mu, yoksa kullanmadığım kod da bundle’a mı giriyor?
★ Chunk’lar makul boyutta mı, yoksa tek dev bir chunk mı var?
⚡ vite-bundle-analyzer ile Kurulum
Vite ekosisteminde benim favorim vite-bundle-analyzer. webpack-bundle-analyzer’ı bilenler için tanıdık bir arayüz sunuyor, hem statik HTML üretebiliyor hem de dev-time’da live bir server açabiliyor. Çok Github Star’ı yok projenin ama işimi gördü bugüne kadar 🥲
Kurulum
npm install -D vite-bundle-analyzer Konfigürasyon
vite.config.ts dosyasına plugin'i ekleyelim:
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { analyzer } from 'vite-bundle-analyzer';
export default defineConfig({
plugins: [
react(),
analyzer({
analyzerMode: 'static', // 'server' | 'static' | 'json' | function
fileName: 'bundle-report',
defaultSizes: 'gzip',
openAnalyzer: true,
}),
],
}); ★ analyzerMode: 'static' → Build sonunda HTML dosyası üretir, CI'da artifact olarak saklanabilir
★ analyzerMode: 'server' → Varsayılan mod; canlı bir server açıp raporu anlık gösterir, dev için ideal
★ analyzerMode: 'json' → İstatistikleri JSON olarak kaydeder, başka araçlarla entegrasyon için kullanışlı
★ analyzerMode: function → Özel bir callback ile çıktıyı tamamen kontrol etmek isteyenler için
★ defaultSizes: 'gzip' → Treemap'te varsayılan olarak gzip sonrası boyutları gösterir (kullanıcıya inen gerçek boyut)
★ openAnalyzer: true → Rapor build biter bitmez otomatik tarayıcıda açılır
Her Build de Değil Sadece “Analyze” scriptinde Çalıştırmak İstersek
Her build’de analyzer’ı çalıştırmak build süresini uzatır. Sadece istediğinizde açılması için environment variable kontrolü ekleyebiliriz:
// vite.config.ts
import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react';
import { analyzer } from 'vite-bundle-analyzer';
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '');
return {
plugins: [
react(),
env.ANALYZE === 'true' && analyzer({ analyzerMode: 'static' }),
].filter(Boolean),
};
}); package.json'a script ekleyin:
{
"scripts": {
"build": "vite build",
"analyze": "ANALYZE=true vite build"
}
} Artık npm run analyze dediğinizde rapor üretilir, normal npm run build hızlı kalır.
🌳 Alternatif: rollup-plugin-visualizer
Vite, Rollup üzerine kurulduğu için Rollup ekosisteminin klasiği rollup-plugin-visualizer da sorunsuz çalışır. Farkı: daha sade, dev-server modu yok, sadece build sonrası HTML üretiyor. Ayrıca çok sayıda farklı görselleştirme template’i sunuyor.
Kurulum
npm install -D rollup-plugin-visualizer Konfigürasyon
vite.config.ts dosyasına plugin'i ekleyelim:
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [
react(),
visualizer({
filename: './dist/stats.html',
template: 'treemap', // 'sunburst' | 'treemap' | 'treemap-3d' | 'network' | 'flamegraph' | 'raw-data' | 'list' | 'markdown'
gzipSize: true,
brotliSize: true,
open: true,
}),
],
}); 💡 rollup-plugin-visualizer'ı her zaman plugins dizisinin en sonuna eklememiz gerekiyor. Plugin'in doğru sonuçlar üretebilmesi için diğer tüm işlemlerin tamamlanmış olması gerekiyor
Hangisini kullanacağınıza karar verirken:
★ webpack-bundle-analyzer arayüzünü seviyorsanız → vite-bundle-analyzer
★ Farklı görselleştirme template’leri deneyip benchmark yapmak istiyorsanız → rollup-plugin-visualizer
★ Sadece CI’da bir kez statik HTML alacaksanız → ikisi de iş görür
🗺️ Bundle Raporunu Okumak
Raporu açtığınızda karşınızda renkli dikdörtgenlerden oluşan bir treemap göreceksiniz. İlk bakışta karmaşık görünür ama mantığı basit:
★ Büyük dikdörtgen → Bundle’da çok yer kaplayan modüller
★ Küçük dikdörtgen → İhmal edilebilir boyutta olan modülller
★ İç içe dikdörtgenler → Paket ve alt modüller
Hover yaptığınızda farklı boyut metriklerini göreceksiniz. Production için odaklanmanız gereken metrik gzipped size’dır, çünkü bu kullanıcının gerçekten indirdiği boyuttur.
Örnek bir rapor senaryosu üzerinden gidelim. Diyelim ki bir admin panel uygulamanızın client bundle’ında şunları görüyorsunuz:
★ react-dom → 135 KB gzipped
★ @tanstack/react-query → 14 KB gzipped
★ framer-motion → 45 KB gzipped
★ recharts → 95 KB gzipped
★ @radix-ui/react-* → 60 KB gzipped
★ Sizin kodunuz → 80 KB gzipped
Toplam ~430 KB gzipped. Buradaki ilk inceleme adayları büyük kütüphaneler: recharts ve framer-motion. Bu kütüphaneler gerçekten her sayfada mı kullanılıyor, yoksa sadece belirli sayfalarda mı? Tree-shaking'den faydalanabiliyor muyuz? Alternatif daha hafif kütüphaneler var mı?
Bundle analyzer bize bu soruları sormamız için gereken veriyi verir. Cevabı ise bizde gizli 😁
🔧 CI/CD Entegrasyonu: Kendi Çözümümüzü Yazalım
PR’a direkt yorum olarak boyut bilgisini yazdıran bir action yazalım:
# .github/workflows/bundle-size-comment.yml
name: Bundle Size Comment
on:
pull_request:
branches: [main]
permissions:
pull-requests: write
contents: read
jobs:
size:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- run: npm ci
- run: npm run build
- name: Calculate sizes
id: sizes
run: |
total=$(du -sb dist/assets/*.js | awk '{sum+=$1} END {print sum}')
gzip_total=$(cat dist/assets/*.js | gzip -c | wc -c)
echo "total=$total" >> $GITHUB_OUTPUT
echo "gzip=$gzip_total" >> $GITHUB_OUTPUT
- name: Comment on PR
uses: actions/github-script@v7
with:
script: |
const raw = (${{ steps.sizes.outputs.total }} / 1024).toFixed(1);
const gzip = (${{ steps.sizes.outputs.gzip }} / 1024).toFixed(1);
const body = `### 📦 Bundle Size\n\n- Total: **${raw} KB**\n- Gzipped: **${gzip} KB**`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body,
}); Bu workflow her PR’a güncel bundle boyutunu yorum olarak bırakır. Ham ve gzipped olarak iki metrik gösterir. Daha fazlasını isterseniz base branch ile karşılaştırma ekleyebilirsiniz ama o noktada hazır paketlere bakmak daha mantıklı gibi
📦 CI/CD Entegrasyonu: Hazır Paketler
size-limit
size-limit, belirli bundle dosyalarınız için hard limit tanımlamanıza izin veriyor. Limiti aşarsanız build kırılıyor.
npm install -D size-limit @size-limit/preset-app package.json'a aşağıdaki kod bloğunu ekleyelim;
{
"size-limit": [
{
"name": "Main Bundle",
"path": "dist/assets/index-*.js",
"limit": "250 KB",
"gzip": true
}
],
"scripts": {
"size": "size-limit"
}
} GitHub Action entegrasyonu ile PR’a tablolu yorum bırakması için:
- uses: andresz1/size-limit-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }} build-size-diff
q1sh101/build-size-diff sıfır konfigürasyon istiyor. Vite, Webpack, Next.js, Nuxt, Astro, Svelte için otomatik algılama yapıyor. Baseline’ı default branch’den alıyor, PR’da diff’i yorum olarak gösteriyor.
name: Bundle Size
on: [push, pull_request]
permissions:
contents: read
pull-requests: write
actions: write
jobs:
size-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: q1sh101/build-size-diff@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }} Raw, gzip boyutlarını tek tabloda karşılaştırıyor, budget enforcement destekliyor. Vite için sıfır konfigürasyon çalışması güzel bir artı.
RelativeCI
RelativeCI, daha gelişmiş takım projesi senaryoları için external bir servis. Historical data, dependency tracking, detaylı compare view’ları sunuyor. Webpack, Vite, Rollup, Rspack destekliyor
Bundle size sadece tek ölçüm yapabilecğimiz veri değil tabii ki. Runtime performans tarafını da ölçmek isterseniz, daha önce yazdığım GitHub Actions ile Lighthouse’u CI/CD Pipeline’ına Entegre Etmek makalesine ve Github’daki Lighthouse Guard projeme göz atabilirsiniz.
📬 Geri Bildirim
Makaleyi yazarken, kaynakları belirleme, araştırma ve yazım denetimi için Claude Opus 4.7 modelini kullandım. Resimleri üretmek için ise Gemini 3 Pro Preview 2k (Nano Banana Pro) modelini kullandım.
Yazı ile ilgili tavsiye, öneri, eleştirileri dikkate alıyorum. İletişime geçmek isterseniz bana websitemdeki sosyal medya adreslerimden veya Linkedin üzerinden ulaşabilirsiniz.
Sevgiyle kalın, Yasin 🤗
📚 Makaleyi Yazarken Kullandığım Kaynaklar
- vite-bundle-analyzer — GitHub — Vite için interaktif bundle analyzer plugin’i
- rollup-plugin-visualizer — GitHub — Rollup/Vite için bundle görselleştirme plugin’i
- Vite Build Options — Vite resmi build dokümantasyonu
- size-limit — GitHub — Bundle size limit enforcement aracı
- build-size-diff — GitHub — Zero-config bundle size diff GitHub Action
- RelativeCI — Otomatik bundle analizi ve monitoring servisi
- webpack-bundlesize-compare-action — GitHub — GitHub’ın resmi bundle size compare action’ı
- https://webpack.js.org/guides/tree-shaking/ — Tree Shaking
- GitHub Actions ile Lighthouse’u CI/CD Pipeline’ına Entegre Etmek — Runtime performans tarafı için önceki makalem
- https://github.com/yasinatesim/lighthouse-guard — CI / CD ye Lighthouse Entegre eden aracım