“Metro yavaş” veya “hot reload çalışmıyor” şikayetlerinin çoğu, bundler’ın siyah kutu kalmasından kaynaklanır. Metro, React Native’in mobil için optimize edilmiş bundler’ıdır — Webpack veya Vite değil. Her npx react-native start arkasında resolution, transformation ve serialization çalışır.
Senior hız: config kopyala-yapıştır değil; hangi dosyanın hangi aşamada seçildiğini ve cache’in ne zaman yalan söylediğini bilmektir.
Pipeline: üç ana stage
1) Resolution: doğru dosyayı bulmak
import './x' veya from '@app/ui' dediğinizde Metro gerçek yolu çözer. metro.config.js içindeki resolver, extraNodeModules, nodeModulesPaths, package.json exports burada devreye girer.
Monorepo’da yanlış resolution sessizce kök node_modules’taki eski React’i seçebilir — duplicate React’in klasik kaynağı. İki React kopyası “Cannot read property useState of null” gibi belirsiz hatalar üretir.
disableHierarchicalLookup: true yukarı doğru rastgele gezmeyi keser; bazı legacy paketleri kırabilir. why duplicate react kontrolünü CI’a ekleyin.
2) Transformation: Babel
Babel TS/JSX → JS dönüşümünü yapar. Plugin sırası kritiktir: Reanimated plugin genelde en sonda olmalıdır; aksi halde worklet’ler transform edilmeden kalır ve release’de animasyon kırılır.
Transformer’da ağır iş — her kaydetmede pahalı AST analizi — dev server’ı öldürür. Analiz CI quality gate’ine aittir.
3) Serialization: bundle ve source map
Modül grafiği tek bundle haline gelir. Source map üretilir. Release’de Hermes hermesc bytecode’a (.hbc) çevirebilir.
Monorepo: watchFolders ve nodeModulesPaths
watchFolders olmadan Metro bazı dosya değişikliklerini algılamaz. “Bazen hot reload olmuyor” şikayetinin büyük kısmı buradan gelir.
Monorepo için tipik metro.config.js:
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const path = require('path');
const workspaceRoot = path.resolve(__dirname, '../..');
const projectRoot = __dirname;
const config = {
watchFolders: [workspaceRoot],
resolver: {
nodeModulesPaths: [
path.resolve(projectRoot, 'node_modules'),
path.resolve(workspaceRoot, 'node_modules'),
],
disableHierarchicalLookup: true,
},
};
module.exports = mergeConfig(getDefaultConfig(projectRoot), config);
Geniş watchFolders = daha yavaş startup; dar = hot reload kaçırır. Doğru denge, gerçekten import edilen paket root’larını kapsamaktır. macOS’ta Watchman kurulu olsun.
Cache: dost ve düşman
Metro agresif cache kullanır. Belirtiler:
- Dependency bump sonrası eski kod çalışıyor
- Babel plugin eklediniz, transform değişmedi
- CI cache hit yüksek ama clean build kırılıyor
Cache sıfırlama:
npx react-native start --reset-cache
rm -rf /tmp/metro-*
CI cache key’e dahil edin: lockfile hash + babel.config + metro.config + RN version + NODE_ENV. Haftalık clean builder job “CI’da geçti, lokalde kırıldı” senaryolarını erken yakalar.
Dev vs release
| Dev | Release | |
|---|---|---|
| Minify | Genelde kapalı | Açık |
| Inline requires | Opsiyonel | Sık açık (TTI için) |
| Source map | Hızlı iterasyon | Crash tooling için zorunlu |
| Hermes | Debug VM | .hbc bytecode |
“Dev’de hızlı, release’de yavaş açılıyor” çoğu zaman inlineRequires, bundle boyutu ve I/O farkındandır. Dev config’i release’e kopyalamayın.
inlineRequires: true cold start iyileştirir; ilk erişimde micro-delay tradeoff’u vardır.
Custom resolver
Platform-spesifik dosya seçimi (.ios.ts, .android.ts) için custom resolveRequest kullanıyorsanız minimal tutun. Hata üretirse Metro sessizce yanlış fallback’e düşebilir.
Asset pipeline ve OTA
require('./logo.png') → packager asset registry. OTA kullanıyorsanız asset’ler bundle ile atomik deploy edilmeli. Büyük PNG’ler Metro’dan geçer ama decode maliyeti UI thread’e yansır — pre-process adımı ekleyin.
Sık tuzaklar
- İki React kopyası —
npm ls react/yarn why react - Package exports uyumsuzluğu
- Symlink + Watchman eksikliği
- Transformer’da ağır iş
- Hermes bytecode adımı OTA ile uyumsuz format
Production checklist
- Monorepo
watchFolders/nodeModulesPathsdoğrulanmış - Duplicate React kontrolü CI’da
- Reanimated Babel plugin sırası dokümante
- Release source map CI artifact
-
--reset-cacherunbook’ta - Hermes bytecode OTA ile aynı format
- Dev ve release config farkları bilinçli
- CI cache key’ine config hash dahil
- Haftalık clean build job aktif
Özet
Metro’yu “start komutu” olmaktan çıkarın. Resolve doğru paket seçer, transform doğru dili üretir, serialize motorun yiyeceği bundle’ı paketler. “Metro yavaş” ticket’ında önce hangi stage’in darboğaz olduğunu ölçün — tahminle config değiştirmeyin.