Ders 20 / 20
Derleme ve Yayın
Geliştirmede hızlı yenileme düğümü yerinde güncellerken tam yeniden yükleme kökü söker. Ders bu farkı ölçer ve yirmi dersin akıbetlerini tek tabloda toplar.
Yayın Güncelleme
Bu derste
- Hızlı yenilemenin düğümü güncellenen ya da korunan bıraktığını ve durumun yaşadığını ölçer
- Tam yeniden yüklemede eski kökün tamamının sökülen, yenisinin kurulan olduğunu gösterir
- Kök tipi değişince hızlı yenilemenin de durumu yitirdiğini ve derleme, imzalama, sürüm kanallarının ağaçta görünmediğini açıklar
- Yirmi dersin akıbetini kapanış tablosunda toplar ve dağılımını sayar
İçindekiler
Önceki ders, yerel modülün ağaçta tek düğüm olduğunu ölçtü. Yerel kod yazılınca uygulama yalnız JavaScript olmaktan çıkar: platform tarafı derlenir, imzalanır ve mağazaya gider. Bu ders kursun kapanışıdır. Önce geliştirme sırasında bir bileşen dosyası değişince ağaçta ne olduğuna bakar, sonra yayın hattını kısaca ayırır, en sonda yirmi dersin akıbetini tek tabloda toplar.
Kursun sorusu: bu güncelleme görünüm ağacındaki düğüme ne yapıyor? Yanıtlar korunan, güncellenen, kurulan ve sökülen; korunan dışındakilerin toplamı komuttur. Kural çekirdek dosyadadır.
// fate.mjs — bir guncellemenin gorunum agacindaki her dugume ne yaptigini siniflandirir export const FATES = ["korunan", "guncellenen", "kurulan", "sokulen"]; export function el(type, props = {}, children = [], key = null) { return { type, props, children, key }; } function segment(node) { return node.key === null ? node.type : `${node.type}[${node.key}]`; } function identity(node, index) { return node.key === null ? `#${index}` : `key:${node.key}`; } function sameProps(a, b) { const names = [...new Set([...Object.keys(a), ...Object.keys(b)])].sort(); return names.every((n) => JSON.stringify(a[n]) === JSON.stringify(b[n])); } function whole(node, path, fate, ops) { const here = `${path}/${segment(node)}`; ops.push({ fate, path: here }); node.children.forEach((child) => whole(child, here, fate, ops)); } export function reconcile(prev, next, path = "", ops = []) { if (prev === null) { whole(next, path, "kurulan", ops); return ops; } if (next === null) { whole(prev, path, "sokulen", ops); return ops; } if (prev.type !== next.type || prev.key !== next.key) { whole(prev, path, "sokulen", ops); whole(next, path, "kurulan", ops); return ops; } const here = `${path}/${segment(next)}`; ops.push({ fate: sameProps(prev.props, next.props) ? "korunan" : "guncellenen", path: here }); const before = new Map(prev.children.map((child, i) => [identity(child, i), child])); const matched = new Set(); next.children.forEach((child, i) => { const id = identity(child, i); matched.add(id); reconcile(before.has(id) ? before.get(id) : null, child, here, ops); }); prev.children.forEach((child, i) => { if (!matched.has(identity(child, i))) reconcile(child, null, here, ops); }); return ops; } export function printOps(ops) { ops.forEach((op) => console.log(`${op.fate}: ${op.path}`)); } export function countFates(ops) { for (const name of FATES) { console.log(`${name}: ${ops.filter((op) => op.fate === name).length}`); } console.log(`komut: ${ops.filter((op) => op.fate !== "korunan").length}`); }
Geliştirme oturumunun modeli ayrı bir dosyadadır. Ekranın kaynağı source nesnesidir: kök düğümün tipi ve başlık metni. buildTree kaynaktan ağacı kurar. Sayaç oturumun durumudur ve ağaca Counter düğümünün özelliği olarak girer. İki yükleme yolu vardır. fastRefresh kaynağı değiştirir ama kök anahtarını korur. fullReload kök anahtarını bir artırır ve sayacı sıfırlar.
// dev.mjs — gelistirme oturumunun modeli import { el, reconcile } from "./fate.mjs"; export function buildTree(source, count, rootKey) { return el(source.root, {}, [ el("Header", { title: source.title }), el("Counter", { count }), ], rootKey); } export function openSession(source) { return { source, count: 0, rootKey: null, tree: buildTree(source, 0, null) }; } export function press(session) { const count = session.count + 1; return { ...session, count, tree: buildTree(session.source, count, session.rootKey) }; } export function fastRefresh(session, source) { const draft = buildTree(source, session.count, session.rootKey); const ops = reconcile(session.tree, draft); const lost = ops.some((op) => op.fate === "sokulen" && op.path.endsWith("/Counter")); const count = lost ? 0 : session.count; const tree = lost ? buildTree(source, 0, session.rootKey) : draft; return [{ ...session, source, count, tree }, ops]; } export function fullReload(session, source) { const rootKey = (session.rootKey ?? 0) + 1; const tree = buildTree(source, 0, rootKey); return [{ source, count: 0, rootKey, tree }, reconcile(session.tree, tree)]; }
Modelin tek kuralı durumun kimliğe bağlı olmasıdır: sayaç, ancak Counter düğümü güncellemeyi aşıp kimliğini koruduysa yaşar. fastRefresh bunu lost ile sınar. Durumu ayrıca saklamak ya da kopyalamak yerine ağacın karşılaştırma sonucuna bakar.
İlk Açılış
Oturum ilk açıldığında önceki ağaç yoktur. Her düğüm kurulandır ve sayaç sıfırdır.
// main.mjs import { reconcile, printOps } from "./fate.mjs"; import { openSession } from "./dev.mjs"; const session = openSession({ root: "App", title: "Ana ekran" }); printOps(reconcile(null, session.tree)); console.log(`sayac: ${session.count}`);
kurulan: /App kurulan: /App/Header kurulan: /App/Counter sayac: 0
Hızlı Yenileme
Kullanıcı sayaca üç kez basar, sonra geliştirici başlığı değiştirir ve dosyayı kaydeder. Hızlı yenileme yalnız değişen bileşen dosyasını yeniden yükler. Kök tipi ve anahtarı aynı kalır.
// main.mjs import { printOps } from "./fate.mjs"; import { openSession, press, fastRefresh } from "./dev.mjs"; let session = openSession({ root: "App", title: "Ana ekran" }); session = press(press(press(session))); const [after, ops] = fastRefresh(session, { root: "App", title: "Baslangic" }); printOps(ops); console.log(`sayac: ${after.count}`);
korunan: /App guncellenen: /App/Header korunan: /App/Counter sayac: 3
Başlık güncellenen çıktı, kök ve sayaç korunan kaldı. Tek komut gitti ve sayaç üçte durdu: yenileme düğümlerin kimliğine dokunmadı, bu yüzden durum yaşadı. Başlığı hiç değiştirmeyen bir kayıt üç düğümü de korunan bırakırdı. Hızlı yenileme, geliştirmede en sık yaşanan akıbet çiftidir: değişen düğüm güncellenen, geri kalan korunan.
Tam Yeniden Yükleme
Her değişiklik hızlı yenilemeyle uyuşmaz. Çizim ağacının dışından içe alınan bir dosya, örneğin uygulamanın başlangıç kodu değişirse bütün paket baştan yüklenir; modelde bunun izi kök anahtarının artmasıdır. Yerel bir modül eklemek bunun da ötesine geçer: paketin yanında platform tarafının yeniden derlenmesini gerektirir.
// main.mjs import { countFates } from "./fate.mjs"; import { openSession, press, fullReload } from "./dev.mjs"; let session = openSession({ root: "App", title: "Ana ekran" }); session = press(press(press(session))); const [after, ops] = fullReload(session, { root: "App", title: "Ana ekran" }); countFates(ops); console.log(`sayac: ${after.count}`);
korunan: 0 guncellenen: 0 kurulan: 3 sokulen: 3 komut: 6 sayac: 0
Kaynak değişmediği hâlde sonuç, hızlı yenilemenin tersidir: üç düğüm sökülen, üç düğüm kurulan, korunan yok. Komut sayısı altı, sayaç sıfır. Kök anahtarı değişince karşılaştırma kökün altına inmez: kök yeni bir düğümdür, eskisi yok olur ve altındaki her düğüm onunla birlikte gider.
Hızlı Yenileme de Kırılabilir
Hızlı yenileme bir ayrıcalık değil, bir koşuldur. Kök tipi değişirse karşılaştırma kökü eşleştiremez. Geliştirici kök bileşenin adını değiştirirse hızlı yenileme de bütün ağacı söker.
// main.mjs import { countFates } from "./fate.mjs"; import { openSession, press, fastRefresh } from "./dev.mjs"; let session = openSession({ root: "App", title: "Ana ekran" }); session = press(press(press(session))); const [after, ops] = fastRefresh(session, { root: "Shell", title: "Ana ekran" }); countFates(ops); console.log(`sayac: ${after.count}`);
korunan: 0 guncellenen: 0 kurulan: 3 sokulen: 3 komut: 6 sayac: 0
Çıktı tam yeniden yüklemeyle aynı, ama yol farklı: burada kök anahtarı değil, kök tipi değişti. İki yol aynı akıbete varır. Durumun yaşayıp yaşamaması hangi komutun kullanıldığına değil, kök düğümün kimliğinin korunup korunmadığına bağlıdır.
Yayın Hattı
Geliştirmede paket, geliştirme sunucusundan gelir. Yayında paket uygulamanın içine gömülür ve iki platformda iki ayrı yoldan geçer. Her platformda yapı üç adımdır: derleme, imzalama, dağıtım. Derleme, JavaScript paketini ve yerel kodu bir araya getirir. İmzalama, paketin kimin tarafından üretildiğini kanıtlar; iki platformda da kendi anahtar yönetimi vardır. Dağıtım, imzalı paketi bir sürüm kanalına koyar: dahili deneme, sınırlı deneme ya da herkese açık yayın.
// Platform kodu: yayin yapilandirmasi (Android)
buildTypes {
release {
isMinifyEnabled = true
signingConfig = signingConfigs.getByName("release")
}
}
Parça iki ayrımı gösterir. release bloğu yayın derlemesinin geliştirme derlemesinden ayrı bir yapılandırma olduğunu, signingConfig satırı da imzanın derleme adımının parçası olduğunu anlatır. iOS tarafında aynı iş proje ayarlarında yapılır; model bunu ayırmaz, çünkü ağaç hangi anahtarla imzalandığını görmez.
Bir kanal daha vardır: uzaktan güncelleme. JavaScript paketi mağaza sürümünden bağımsız olarak değiştirilebilir. Sınır şudur: yalnız JavaScript tarafı uzaktan değişir. Yerel modülün yeni bir sürümü, yeni bir izin ya da yeni bir yerel görünüm yeni bir mağaza sürümü ister. Bu yüzden önceki dersteki NativeMap düğümü uzaktan güncellemeyle yeniden yazılabilir ama haritanın yerel kodu yazılamaz.
Yaygın Yanılgılar
İlk yanılgı, hızlı yenilemenin her zaman durumu koruduğudur. Yukarıdaki kök tipi ölçümü bunun tersini gösterdi: kök tipi değişince durum yitirildi. Hızlı yenileme bir güvence değil, ağacın karşılaştırma sonucuna bağlı bir sonuçtur.
İkinci yanılgı, tam yeniden yüklemenin uygulamayı yeniden başlatmak olduğudur. Model uygulamayı değil, kökü yeniden kurar. Telefon sürecinin ayakta kalması ya da kalmaması ağaç kuralının dışındadır; kural yalnız ağaçtaki düğümlere ne olduğunu söyler.
Üçüncü yanılgı, yayın yapılandırmasının ağaca yansıdığıdır. Derleme türü, imza ve sürüm kanalı düğümlerin tipini ya da özelliklerini değiştirmez. Aynı kaynak hem geliştirme hem yayın paketinde aynı ağacı üretir; farklı olan, ağaca ulaşan paketin nereden geldiğidir.
Sınırlayıcı Ölçüm
Bu dersin ayrım sorusu bu değişiklik nereye ulaşıyor (M12/K02) sorusudur. O soru bir kod değişikliğinin yayılımını sorar: yerinde, bağlantıda, kıran ya da örtük. Bu kurs kodun değil, çalışma anındaki tek bir güncellemenin tek bir düğüme etkisini sınıflar. Hızlı yenilemede kod değişikliği yerinde yayılır; ağaçta bıraktığı iz ise başlık düğümünde güncellenen, geri kalanda korunandır. İki sorunun cevabı birbirinden bağımsızdır.
Son ölçüm eski kökü gösterir. Tam yeniden yükleme kökte yapılır; kural yalnız kök düzeyindeki kayıtlara süzülür.
// main.mjs import { printOps } from "./fate.mjs"; import { openSession, press, fullReload } from "./dev.mjs"; let session = openSession({ root: "App", title: "Ana ekran" }); session = press(press(press(session))); const [after, ops] = fullReload(session, { root: "App", title: "Ana ekran" }); printOps(ops.filter((op) => op.path.split("/").length === 2)); console.log(`komut: ${ops.filter((op) => op.fate !== "korunan").length}`);
sokulen: /App kurulan: /App[1] komut: 6
Odak düğüm eski kök /App. Sökülen çıktı; yenisi /App[1] anahtarıyla kurulan. Eski kök gidince altındaki başlık ve sayaç da sökülen kaydı aldı: komut altı. Sökülen düğüm kimliğini yitirir, yani sayaç üçten sıfıra döndü. Güncellenen bir kök kimliğini korurdu.
BU7. Model, bu akıbetin kuralını kurar; model çerçevenin kendisi değildir. Modelde hızlı yenileme ağacı kaynaktan baştan kurar ve karşılaştırır; gerçek bir hızlı yenileme yalnız değişen dosyayı yeniden değerlendirir ve durumu tutmak için kendi kurallarını uygular. Modelde kök anahtarı elle artırılır; gerçek bir tam yeniden yükleme paketi baştan yükler ve bunun bedeli, geliştirme sunucusunun bağlantısı model dışındadır. Yayın hattı da modelde yoktur: derleme, imzalama ve mağaza süreçleri ağaç kuralının girdisi değildir.
Kapanış Tablosu
Kurs boyunca yirmi güncelleme ölçüldü. Her satır bir dersin akıbetini ve o dersin sınırlayıcı ölçümünde odaklanılan düğümü verir. Akıbet hücreleri kaynak dersin Özet bölümünden alınmıştır.
| Ders | Ölçülen güncelleme | Akıbet | Sınırlayıcı ölçüm |
|---|---|---|---|
| React Native Nedir | sayaç ağaca girmeyen değişkende artar | korunan | /Screen/Text, komut 0 |
| Ortam Kurulumu | kabuktan sonraki ilk güncelleme | kurulan | /App/Home, alt ağacıyla |
| Çekirdek Bileşenler | yer tutucu görselle değişir | sökülen | /Card/Text |
| Biçem Sistemi | içeriği aynı biçem nesnesi gelir | korunan | /Row/Box, komut 0 |
| Dokunma ve Etkileşim | basılı durum özellik olur | güncellenen | /Screen/Button |
| Platforma Özgü Kod | iki platformun ağacı karşılaştırılır | kurulan | /Settings/Toggle |
| Gezinme | yeni rota itilir | korunan | /Stack/Screen[liste] |
| Durum Yönetimi | sepet sayısı değişir | güncellenen | /Screen/Header/Badge |
| Ağ ve Veri | veri gelir | sökülen | /Feed/Spinner |
| Yerel Depolama | açılışta taslak okunur | kurulan | /Editor/Draft |
| Güvenli Depolama | oturum kapanır | sökülen | /App/Account |
| Bildirimler ve Derin Bağlantı | bağlantı açılır | kurulan | /Stack/Screen[siparis-42] |
| Hareketler ve Animasyonlar | hareket yerel tarafta sürer | korunan | /Deck/Card, komut 0 |
| Liste Başarımı | başa öge eklenir | güncellenen | /Inbox/Row |
| Kare Hızı ve Profilleme | ağaç üç kez yeniden üretilir | korunan | /Screen/Chart |
| Paket Boyutu ve Başlangıç | ertelenmiş ekran yüklenir | kurulan | /App/Reports |
| Hata Ayıklama Araçları | alt ağaç hata verir | sökülen | /Screen/Panel |
| Test | düğmeye basılır | güncellenen | /Counter/Text |
| Yerel Modül Yazımı | harita merkezi değişir | güncellenen | /Screen/NativeMap, komut 1 |
| Derleme ve Yayın | tam yeniden yükleme | sökülen | /App, komut 6 |
Derslerin dağılımı: korunan 5 (React Native Nedir, Biçem Sistemi, Gezinme, Hareketler ve Animasyonlar, Kare Hızı ve Profilleme), güncellenen 5 (Dokunma ve Etkileşim, Durum Yönetimi, Liste Başarımı, Test, Yerel Modül Yazımı), kurulan 5 (Ortam Kurulumu, Platforma Özgü Kod, Yerel Depolama, Bildirimler ve Derin Bağlantı, Paket Boyutu ve Başlangıç), sökülen 5 (Çekirdek Bileşenler, Ağ ve Veri, Güvenli Depolama, Hata Ayıklama Araçları, Derleme ve Yayın).
Bu dağılım, çekirdek dosyanın açılış sayımıyla aynı şey değildir. Çekirdeğin açılış sayımı tek bir güncellemenin sekiz düğümünü sayar: korunan 5, güncellenen 1, kurulan 1, sökülen 1 ve komut 3. Tablo ise yirmi dersin her birinin akıbetini sayar. Biri düğüm, öteki ders sayar.
Özet
- Bu dersin akıbeti: sökülen. Tam yeniden yüklemede eski kök
/Appkök anahtarı değiştiği için sökülen çıktı; yenisi kurulan oldu, altındaki üç düğümle komut altı. - Hızlı yenileme değişen düğümü güncellenen, geri kalanı korunan bırakır; durum yaşar. Kök tipi ya da anahtarı değişince durum yitirilir.
- Derleme, imzalama ve sürüm kanalı ağaçta görünmez; uzaktan güncelleme yalnız JavaScript tarafını değiştirir.
- Yirmi dersin akıbeti beşer beşer dağılır: korunan, güncellenen, kurulan ve sökülen beşer ders.
Sonraki Adım
Bu kurs, ortak kodu platformun yerel görünümlerine tarif olarak ileten bir çerçeveyi ölçtü. Sıradaki kurs, ekranı platformun görünümlerine bırakmayıp kendi çizim motoruyla çizen bir çerçeveyi ele alır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.