İçeriğe geç
academia.sh

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 /App kö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.

Aramak için yazmaya başlayın.

↑↓ ↵ Esc gezin · aç · kapat