Monorepo kavramını incelediğimizde, çoğu zaman gözden kaçırdığımız önemli bir konu var: projedeki paketlerin nasıl yönetileceği
. Bu da bizi doğrudan şu soruyu düşündürüyor: Monorepo kullanırken paketleri hangi stratejiyle yönetmeliyiz?
Bu yazımda, benim de Turborepo deneyimlerimle öğrendiğim monorepo mimarisinin paket yönetimi yaklaşımını ve bu yaklaşımlarda çoğu zaman başımıza gelen çakışma durumunu nasıl çözeceğimizi ele alacağım.
Monorepo'nun temel amacı, kodun yeniden kullanımını artırmak. Mantık basit: packages
klasöründeki paylaşılan bir kütüphaneyi, apps
klasöründeki uygulamalarınızda kullanmak. Kulağa kolay gelse de, bu paylaşımı teknik olarak nasıl yapacağınız, özellikle de monorepoyla yeni tanışıyorsanız, başta kafa karıştırıcı olabilir.
Bağımlılıklar: dependencies
, devDependencies
ve peerDependencies
Paket yönetimi deyince akla ilk gelenler dependencies
ve devDependencies
'tır. Bunlar çoğu zaman yeterli olsa da, monorepo gibi ortamlarda peerDependencies
kavramını iyi anlamak şart.
dependencies
: Uygulamanızın çalışması için kesinlikle ihtiyaç duyduğu paketler. Örneğin, React projenizdereact
gibi.devDependencies
: Geliştirme sürecinde ihtiyaç duyduğunuz ama uygulamanızın çalışması için şart olmayan paketler. Test araçları (Jest) veya lint araçları (ESLint) gibi.
peerDependencies
Nedir?
peerDependencies
, bir paketin doğru çalışması için başka bir paketin belirli bir sürümüne "ihtiyaç duyduğunu" belirtir, ancak o paketi kendisi yüklemez. Bunun yerine, bu paketin kullanıldığı "üst" projenin (yani monorepo'daki uygulamanızın) o bağımlılığı sağlamasını bekler.
Şöyle düşünün: Bir UI bileşenleri kütüphanesi yazdınız (@monorepo/ui-components
). Bu kütüphane React'e bağımlı. Eğer siz react
'i doğrudan dependencies
olarak @monorepo/ui-components
'e eklerseniz, bu kütüphaneyi kullanan her uygulama kendi node_modules
klasörüne React'in bir kopyasını indirecek. Bu, aynı React sürümünü kullanan birden fazla uygulamanız varsa gereksiz yere disk alanı tüketimi ve potansiyel sürüm çakışmaları yaratır.
İşte burada peerDependencies
devreye giriyor. @monorepo/ui-components
paketinizin package.json
dosyasına şunu yazabilirsiniz:
{
"name": "@monorepo/ui-components",
"version": "1.0.0",
"peerDependencies": {
"react": ">=19.0.0",
"react-dom": ">=19.0.0"
}
}
Bu, @monorepo/ui-components
paketini kullanan her uygulamanın (örneğin apps/web
) kendi package.json
dosyasına react
ve react-dom
'u eklemesini bekler. Eğer uygulama bu bağımlılıkları sağlamazsa, paket yöneticiniz size bir uyarı verir.
Çakışan Paketleri Nasıl Çözeriz?
peerDependencies
uyarıları veya hataları, paket sürümlerinde bir tutarsızlık olduğunu gösterir. Örneğin, ui-components
React 19 isterken, apps/web
React 18 kullanıyorsa. Bu durumu çözmek için birkaç yöntemimiz var:
1. Sürümleri Eşitlemek (En İdeal Yaklaşım)
En sağlıklı çözüm, çakışan paketin sürümünü monorepo genelinde eşitlemektir.
-
Kök
package.json
'da Tanımlama: Çakışan paketi (örneğinreact
) monoreponuzun kökpackage.json
dosyasına ekleyin. Böylece tüm çalışma alanları aynı bağımlılığı tek bir yerden alır.{ "name": "my-monorepo", "version": "1.0.0", "private": true, "workspaces": ["apps/*", "packages/*"], "dependencies": { "react": "^19.0.0", // Ortak React sürümü "react-dom": "^19.0.0" } }
-
Uygulamaların Karşılaması:
apps/web
gibi uygulamalarınızınpackage.json
'ına,ui-components
'inpeerDependencies
olarak beklediği paketleri (React) ekleyin ve bu sürümü kökpackage.json
'daki ile uyumlu tutun.{ "name": "web", "version": "1.0.0", "dependencies": { "@monorepo/ui-components": "workspace:*", "react": "^19.0.0", // Kökten gelen sürümle uyumlu "react-dom": "^19.0.0", "next": "^15.0.0" } }
Turborepo, pnpm veya yarn workspaces gibi araçlar, bu bağımlılıkları otomatik olarak kök
node_modules
'a taşıyarak (hoisting) çakışmaları azaltmaya yardımcı olur.
2. Paket Yöneticisi Özel Çözümleri
Bazı durumlarda, tüm bağımlılıkları eşitlemek zor olabilir. Paket yöneticileri bu durumlar için özel çözümler sunar:
-
pnpm
/yarn
resolutions /npm
overrides: Monoreponuzun kökpackage.json
'ında bu alanları kullanarak belirli bir bağımlılığın zorla belirli bir sürümünü kullanmasını sağlayabilirsiniz. Bu, esnek olmayan ama etkili bir çözümdür.{ "name": "my-monorepo", // ... "resolutions": { // veya "overrides" (npm için) "react": "18.2.0", "react-dom": "18.2.0" } }
Sonuç Olarak
Monorepo'larda bağımlılık çakışmaları kaçınılmazdır. Önemli olan, peerDependencies
kavramını doğru anlayarak ve sürümleri eşitleme ya da paket yöneticilerinin resolutions
/overrides
gibi özelliklerini kullanarak bunları etkili bir şekilde çözmektir. Temel hedef, tüm bağımlılıkları monorepo genelinde tutarlı tutmaktır. Bu, geliştirme akışını düzene sokar ve daha stabil bir proje yapısı sağlar.
Sonraki yazımda görüşmek üzere. Hoşçakalın…