Bir özellik yayınımızı tamamladıktan kısa bir süre sonra, mühendislerimizden biri kullanıcı arayüzünde dikkat çeken bir sorun fark etti. Geliştirme ortamında kusursuz çalışan bileşenlerin genişliği, canlı ortamda bozulmuştu. Hemen müdahale etmek yerine, bu farklılığın ardındaki gerçek nedeni araştırmaya karar verdik.
Geliştirme ve Üretim Ortamları Arasındaki Farkın Kökeni
Sorunlu öğe, bir form etiketiydi. İki farklı CSS Modül kuralı tarafından aynı anda stillendiriliyordu:
/* Ortak bileşen — time-range-group-field.module.css */
.label { width: 20.75rem; }
/* Sayfa özel — scheduler-form.module.css */
.fieldLabel { width: 11rem; }Ortak bileşen, aşağıdaki gibi içsel olarak çalışıyordu:
<label className={mergeClassNames(styles.label, labelClassName)}>Label</label>Bu durumda, tarayıcı hangi genişlik değerinin geçerli olacağını belirlemek zorunda kaldı. Her iki kuralın da eşdeğer özgüllüğü (0,1,0) vardı. Özgüllük eşit olduğunda, CSS kaynak sırasına başvurur: stil dosyasında daha sonra yer alan kural geçerli olur.
Geliştirme ortamında özel stilimiz (11rem) daha sonra geldiği için galip gelmişti. Üretim ortamında ise ortak stil (20.75rem) daha sonra yer aldığından, o kazanmıştı. Aynı kodun farklı sonuçlar üretmesi, derleme sürecindeki farklılıklardan kaynaklanıyordu.
Kaynak Sırasının Neden Değiştiğini Anlamak
Geliştirme ortamında Next.js, CSS dosyalarını ayrı <style> etiketleri olarak enjekte eder ve JavaScript ithalat sırasına göre DOM’a eklenir. Bu durumda, alt modüllerin stilleri genellikle daha sonra gelir ve yerel stiller varsayılanları geçersiz kılar. Bu davranış yanıltıcıdır çünkü kaynak sırası üretimde garanti edilmez.
Üretimdeyse, Next.js derlemesi Turbopack kullanır ve stilleri out/_next/static/chunks/ klasörüne toplu olarak yerleştirir. Turbopack, paylaşılan modüllerin birden fazla ithalat yoluyla erişilebilir olması durumunda kaynak sırasını değiştirebilir. Bu da geliştirme ortamındaki davranışla çelişen sonuçlara yol açar.
Kalıcı Çözüm: :where() ve Sıkı CSS Parçalama
İlk olarak, ortak bileşenin varsayılan stilini daha zayıf bir özgüllüğe indirgemek için :where() fonksiyonunu kullandık:
:where(.label) { width: 20.75rem; padding-top: 0.5rem; }:where() seçicinin özgüllüğünü sıfıra düşürür. Artık varsayılan stil (0,0,0) herhangi bir dışsal sınıf (0,1,0) tarafından otomatik olarak geçersiz kılınabilir. Kaynak sırası bağımlılığı ortadan kalkar ve gelecekteki stiller için daha temiz bir çözüm sunar.
Ek bir önlem olarak, next.config.ts dosyasında experimental.cssChunking: 'strict' ayarını aktifleştirdik:
experimental: {
cssChunking: 'strict',
}Bu ayar, Next.js’in farklı modüllerden gelen CSS dosyalarını birleştirirken kaynak sırasını korumasını sağlar. Böylece gelecekteki benzer sorunların önüne geçilmiş olur.
Gelecek için Alınan Dersler
Geliştirme ve üretim ortamları arasındaki tutarsızlık, genellikle deterministik olduğunu düşündüğümüz bir şeyin aslında öyle olmadığını gösterir. Bu durumda, kaynak sırası gibi görmezden geldiğimiz bir faktör, beklenmedik hatalara yol açtı.
Bu sorunu çözmek için alınabilecek genel ders, varsayılan stillerin öngörülebilir ve geçersiz kılınabilir olmasını sağlamaktır. Ortak UI bileşenleri geliştirirken, her "varsayılan" stilin :where() ile sarılması, gelecekteki uyumsuzlukları engellemenin basit ve etkili bir yoludur. Gereksiz zorluklarla uğraşmak yerine, bileşenlerinizi geleceğe hazır hale getirin.
Yapay zeka özeti
Geliştirme ve üretim ortamlarında CSS stillerinin farklı çalışmasının nedenlerini keşfedin. `:where()` fonksiyonu ve sıkı CSS parçalama ayarlarıyla sorunu kalıcı olarak çözün.