Yasin Ateş

Bundle Analyzer ile React Projelerini İncelemek

Bundle Analyzer ile React Projelerini İncelemek

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

Bundle Analyzer Browser görünümü

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

  1. vite-bundle-analyzer — GitHub — Vite için interaktif bundle analyzer plugin’i
  2. rollup-plugin-visualizer — GitHub — Rollup/Vite için bundle görselleştirme plugin’i
  3. Vite Build Options — Vite resmi build dokümantasyonu
  4. size-limit — GitHub — Bundle size limit enforcement aracı
  5. build-size-diff — GitHub — Zero-config bundle size diff GitHub Action
  6. RelativeCI — Otomatik bundle analizi ve monitoring servisi
  7. webpack-bundlesize-compare-action — GitHub — GitHub’ın resmi bundle size compare action’ı
  8. https://webpack.js.org/guides/tree-shaking/ — Tree Shaking
  9. GitHub Actions ile Lighthouse’u CI/CD Pipeline’ına Entegre Etmek — Runtime performans tarafı için önceki makalem
  10. https://github.com/yasinatesim/lighthouse-guard — CI / CD ye Lighthouse Entegre eden aracım