Yazılımcı Masalları
Masal 1
Script yerini bilir mi?
Katmanya’da, +2 Evler katında geçiyor. Kod var; kodu okumadan da masal takip edilir.
Merhaba, ben Kaşif Oğuz. Bugün +2’deyiz, Evler’de. Burada her ev bir sayfa, her oda sayfadaki bir öğe.
Kapının önünde küçük bir yolcu bekliyor. Elinde bir zarf var. Zarfın içinde göstereceği şey yazılı: bir sohbet penceresi. Zarfın üstünde adres yok.
Yolcunun adı Script. Başka bir yerden geldi, bu evi hiç görmedi. Ev sahibi onu çağırdı, çünkü sayfasında bir sohbet penceresi istiyor.
Bugüne kadar pencere evin köşesinde yüzüyordu. Şimdi ev sahibinin isteği başka: pencere bir ürünün hemen altında dursun.
Peki yolcu o yeri kendi kendine bulabilir mi?
Önce şunu oku İki Hayalet: null ve undefinedBen neredeyim?
Script’in ilk fikri basit: kapıda beni nereye bıraktılarsa orası benim yerimdir.
Tarayıcı bu soruya cevap verir. Script çalışırken kendi etiketini sorabilir, pencereyi de etiketin hemen yanına çizer. Kâğıt üstünde iki satır.
const me = document.currentScript;
me.after(chatWindow);
Bir şartı var. Script klasik bir script olmalı ve o anda ilk kez çalışıyor olmalı. Modül script’te ya da sonradan çalışan bir geri çağrıda cevap null gelir.
O zaman kapıya Sandalye Hayaleti gelir ve boş sandalyesini bırakır. Sandalyeyi koyan Script değil, tarayıcı.
Bu sahnedeki yaratık İki HayaletKapıdaki görevli.
Kapıda bir görevli duruyor. Elinde ev sahibinin listesi var. Listede adı olan yolcuyu içeri alır.
Görevli düzen sever. Bütün yolcuları aynı yere dizer: giriş holüne (<head>) ya da koridorun en sonuna. Hangi yolcunun hangi odaya gideceğini bilmez. Sayfayı yöneten başka araçlar da script’i böyle taşır.
Script holde uyanır ve sorar: ben neredeyim? Tarayıcı doğru söyler. Etiket gerçekten holde.
Yanlış olan cevap değil, yer. Script’in durduğu yer, içeriğin yeri değil.
Bekçi plana bakar.
Evin üst katında bekçiler oturur. Her birinin elinde bir plan var. Sayfanın framework’ü budur: React, Vue ve ötekiler.
Bekçiler odaları dolaşıp denetlemez. Yalnızca kendi planlarının eski ve yeni hâlini karşılaştırır, değişen yeri yeniden örer. Kendi yapmadıkları bir oda sıradan bir güncellemede çoğu zaman yerinde kalır.
Ama bekçi bir duvarı baştan örerse içindeki yabancı oda da gider. Ne zaman mı? Bir parça koşula bağlı çizilip silinince, key değişince, sayfa içinde başka sayfaya geçilince. Bekçi evi ilk kurarken de kabın içini boşaltır.
Vue bekçisi bir adım daha atar. Planda bir <script> görürse onu plandan siler ve uyarı yazar. Yolcu hiç doğmaz. Plan sayfanın HTML’inde duruyorsa durum farklı: tarayıcı script’i bir kez çalıştırır, Vue sonra gelip etiketi kaldırır.
Tags with side effect (<script> and <style>) are ignored in client component templates.
Uyutulan yolcu.
React bekçisi yolcuyu silmez, içeri alır. Etiket odada durur. Ama yolcu uyanmaz.
Bu bilerek seçilmiş. async ve src verilmeden çizilen script’i React, sayfaya HTML metni yazar gibi kurar. Tarayıcı bu yolla gelen script’i çalıştırmaz.
Aynı kural ev sahibi için de geçerli. Script’i innerHTML, v-html ya da dangerouslySetInnerHTML ile bir odaya yazarsan yolcu uyumaya devam eder. HTML standardı böyle diyor.
room.innerHTML = '<script src="chat.js"></script>';
// the tag is in the room, the script never runs
Burada benzetme kırılıyor: uyuyan yolcu güvenli demek değil. Aynı yolla gelen bir resmin onerror notu çalışır. innerHTML bir kalkan değil.
Uyanık ama yanlış katta.
React 19’da bekçinin yeni bir kuralı var. Script’e src ve async verirsen onu uyutmaz. Onu <head> odasına taşır. Aynı adresten ikinci bir yolcu gelirse onu içeri almaz, tek kopya tutar.
<script src="chat.js" async={true} />
Yolcu uyanır ve çalışır. Ama artık ürünün yanında değil.
Bir yol daha var. Sayfa sunucuda hazırlanıp ilk HTML ile gelirse içindeki script’i tarayıcı sayfayı okurken çalıştırır.
Silinen, uyuyan, taşınan. Script’in kendi yerini bulup bulamayacağı, o evde hangi bekçinin hangi kuralla çalıştığına bağlı. Yolcu bunu kapıdan bilemez.
İki yanlış kapı.
Ev sahibi başka bir şey dener. Duvara yol tarifi yazar: “ikinci koridor, soldan üçüncü oda”. Bu bir CSS selector.
Evde tadilat olur. Tarif artık yanlış odayı gösterir. Birinin her tadilattan sonra tarifi düzeltmesi gerekir. Sayfa üstünde deney yapan araçlar tam bu yükü taşır. Bu yol şimdilik ertelendi.
Sonra yolcuya ayrı bir oda verilir: iframe. Video oynatıcılar böyle yapar. Oda evin içinde durur ama penceresi yoktur. Başka bir adresten açılan oda evi göremez. Ürünü, kullanıcıyı, sayfanın durumunu bilmez.
Ev sahibi kapının altından not atmazsa (URL parametresi, postMessage) yolcu hiçbir şey öğrenemez. Sohbet penceresinin işi ise tam o bilgiye bağlı. Bu kapı da kapandı.
Duvardaki çerçeve.
Sonunda ev sahibi kendi eliyle bir şey yapar. Ürünün altına boş bir çerçeve asar ve üstüne bir ad yazar: A1.
<div data-widget-id="A1"></div>
Script hangi odada uyanırsa uyansın önce bu çerçeveyi arar. Bulur, içine yerleşir. Yeri ev sahibi seçti, yolcu tahmin etmedi.
Bekçiler boş çerçevenin içine dokunmaz. Ama duvarı yeniden örerlerse çerçeve yenisiyle değişir ve boş gelir. Yolcu yeni çerçeveyi yeniden bulmalı, örneğin sayfadaki değişiklikleri izleyerek (MutationObserver). Sayfa sunucuda hazırlanıyorsa ve yolcu bekçiden önce çizerse plan ile ev uyuşmayabilir.
Masada bir seçenek daha var: <my-widget widget-id="A2">. Tarayıcı adında tire olan bu etiketi tanımasa da yerinde bırakır, “henüz tanımlanmamış” diye bekletir, tanım gelince yükseltir. Daha temiz görünüyor. Olumsuz yanlarına hâlâ bakılıyor, karar verilmedi.
Bu sahnedeki yaratık Boncuk ÖrümceğiHaberci kuş ve kendi zili.
Yolcunun bilmediği bir şey daha var: ben yüzen pencere miyim, çerçevedeki mi? Bunu ev sahibi seçmez.
Merkezden bir haberci kuş gelir. Ayağında yapılandırma kaydı var: bir object. Çekmece Kaplumbağası’nın “tür” çekmecesinde cevap yazıyor. Yolcu cevaba göre gereken eşyayı sonradan çağırır (dynamic import). Kapıdan tek yolcu girer, iki işi de yapar. Ev sahibi yanlış türü seçemez, çünkü hiç seçmiyor. Çerçevedeki pencerenin kendi kimliği de var, sayımda yüzen pencereyle karışmasın diye.
Bazı ev sahiplerinin kendi zili var. Pencerenin simgesini gizler, sohbeti kendi düğmeleriyle açarlar. Zil bir function: open().
open(); // opens the page's widget, as before
open("A2"); // opens the copy with this id
Adsız zil eskisi gibi çalar. O zaman ad için Gelmeyen Hayalet bekler. Adı bilinmeyen ya da henüz açılmamış bir zil sesi bekletilir. O kopya hiç açılmazsa çağrı düşer ve sebebi deftere yazılır. Eski zil bozulmadı, yanına isteğe bağlı bir ad eklendi.
Bu sahnedeki yaratık Çekmece Kaplumbağası Bu sahnedeki yaratık Çevirgen Solucanİkizler kapıda.
Bir gün kapıya iki yolcu daha gelir. Evde iki çerçeve var, köşede de yüzen bir pencere. Kim nereye gidecek?
Bunun cevabı henüz yok. Gerçek evlerde bu ihtiyaç var. Şimdilik kural şu: evde tek kopya çalışır. İkizlere “biraz bekleyin” deniyor. Kapı kilitlenmedi. Altyapı ileride açılacak şekilde tutuluyor.
Ev sahibi aynı script’i iki kez eklerse ne olur? Modül script ise tarayıcı aynı adresi bir kez çalıştırır. Klasik script’te iki etiket iki kez çalışır. Bunu bu projede biz denemedik.
Bu evde kimse kötü değil. Görevli listesine, bekçi planına, yolcu kendi işine sadık. Yerini bilen yolcu değil, yerini hazırlayan ev sahibi.
Dürüst not.
- Kaynak bir konuşma özeti. Kararlar tasarım dokümanı ya da kodla teyit edilmedi.
- React ve Vue davranışlarını kaynak kodlarından ve belgelerinden okuduk. Hiçbirini kendimiz bir sayfada çalıştırmadık.
- Aynı src’nin bir kez yüklenmesi modül script için standartta yazıyor. Bu projede denemedik.
- Bekçilerin bir duvarı ne zaman yeniden ördüğü framework’e ve sürüme göre değişiyor. Masalda üç örnek var, tam liste yok.
- Custom element mi, div mi: karar verilmedi.
- Aynı sayfada birden çok pencere desteklenmiyor. İhtiyaç gerçek, iş park edildi.
- Ev sahibi sonradan sayfa içi pencere eklerse script’ini güncellemesi gerekecek mi, belli değil.
- “Sıra sende”deki denemeyi bu metni yazarken çalıştırmadık.
Sıra sende
Herhangi bir sayfada geliştirici araçlarını aç (çoğu tarayıcıda F12), Console sekmesine şunu yaz:
document.currentScript
Cevabı önce tahmin et. Konsola yazdığın satırı tarayıcı bir <script> etiketini ilk kez işlerken çalıştırmıyor.
Kapıya kim gelir?
Kaynak notu: kararlar bir iş konuşmasının özetinden, ayrıntıları çıkarılarak alındı. React, Vue ve HTML standardıyla ilgili iddialar kaynak kodlarından ve belgelerinden okundu.
Fikirler ve hikâyeler Oğuz’dan. Metinleri ve çizimleri yapay zekâyla birlikte üretiyoruz; her sayfayı Oğuz okuyup onaylıyor. Bir DemirCraftCo işi.
Başa dön