Rehberler
Paketler için DevTools
Paketler için registerDevtools (describe, inspect, sources, commands, panels, olaylar, reveal), operation'lar ve yazma kayıtları; bir paketin kendi DevTools panelinin çekirdek tarafı.
Bir paket (bileşen kütüphanesi, veri katmanı, store) bir DevTools arayüzüne bağımlı olmadan kendi durumunu DevTools'ta gösterebilir: çekirdeğe kaydolur, arayüz verdiğini okur. Bu sayfa çekirdek tarafını anlatır: registerDevtools ne alır, tutamacı ne yapar, paket hangi işin neyi değiştirdiğini nasıl söyler. Arayüzün okuduğu nesne DevTools sözleşmesi sayfasındadır. @motifx-community/devtools panelinin panel metadata'sından ne çizdiği, widget'ları, route'ları ve sınırları o paketin docs/extensions.md dosyasında anlatılır, burada değil.
Paketler için registerDevtools
Bir paket kendi durumunu @motifx/core/devtools alt yolundan açar. describe ve inspect veri verir; sources, commands ve panels ile arayüz istediğinde okur, sayfaya komut gönderir ve ne çizeceğini bilir. Örnekte Üçüncü Parti Kütüphane Sarmalama sayfasındaki klasör grafiği, kurduğu grafikleri bileşene göre tutar ve verisini DevTools'a verir:
import { registerDevtools } from "@motifx/core/devtools";
import type { ComponentBase } from "@motifx/core";
import type { Chart } from "chart.js/auto";
const charts = new Map<object, Chart>();
const devtools = registerDevtools("folder-chart", {
describe: () => ({ charts: charts.size }),
inspect: (component) => charts.get(component)?.data.datasets[0].data,
sources: {
charts: { read: () => [...charts.values()].map(summaryOf), key: "id", events: { update: "refresh" } },
chart: { read: (params: { id: string }) => detailOf(params.id) },
},
commands: {
redraw: (args: { id: string }) => chartById(args.id)?.update(),
},
panels: [{
id: "charts", title: "Folder charts", icon: "chart", order: 40,
capabilities: { read: true, subscribe: true, write: true },
layout: { /* arayüzün çizeceği şey; onun kendi şeması */ },
}],
});
function track(canvas: ComponentBase, chart: Chart) {
charts.set(canvas, chart);
canvas.motif.setDisposable(() => charts.delete(canvas));
}
function updated(canvas: ComponentBase, counts: number[]) {
devtools.emit("update", { path: devtools.pathOf(canvas), counts });
devtools.changed("charts");
}
import { registerDevtools } from "@motifx/core/devtools";
const charts = new Map();
const devtools = registerDevtools("folder-chart", {
describe: () => ({ charts: charts.size }),
inspect: (component) => charts.get(component)?.data.datasets[0].data,
sources: {
charts: { read: () => [...charts.values()].map(summaryOf), key: "id", events: { update: "refresh" } },
chart: { read: (params) => detailOf(params.id) },
},
commands: {
redraw: (args) => chartById(args.id)?.update(),
},
panels: [{
id: "charts", title: "Folder charts", icon: "chart", order: 40,
capabilities: { read: true, subscribe: true, write: true },
layout: { /* arayüzün çizeceği şey; onun kendi şeması */ },
}],
});
function track(canvas, chart) {
charts.set(canvas, chart);
canvas.motif.setDisposable(() => charts.delete(canvas));
}
function updated(canvas, counts) {
devtools.emit("update", { path: devtools.pathOf(canvas), counts });
devtools.changed("charts");
}
- Kayıt her zaman yapılabilir; paket import edildiği anda kayıt olabilir.
describe,inspect,sources,commandsve fonksiyon olarak verilenpanelsyalnız arayüz istediğinde çağrılır. describe()sonucureadExtension(ad)ile,inspect(component)sonucuinspect(path).extensions[ad]içinde okunur.undefineddönen paket o bileşen için listelenmez.- Hata fırlatan bir fonksiyonun sonucu
{ error }(describe,inspect) ya da{ ok: false, error }(kaynaklar, komutlar,panels) olur; diğer veriler etkilenmez. panelsarayüzün bu paket için ne çizeceğini söyler:id,title,icon,order,capabilitiesve arayüzün kendi şemasının tanımladığı başka ne varsa (layout,routes). Çekirdek onu olduğu gibi saklar, yalnızidvecapabilities'i okur. Fonksiyon olarak verilirse her okumada çağrılır.readExtensionPanels(ad){ panels, sources, commands }döner: paneller, her kaynağınread'i dışındaki ayarları (key,events,max) ve komut adları.sourcesarayüzün parametreyle okuduğu adlı fonksiyonlardır.readExtensionSource(ad, panel, kaynak, params)read(params)'ı bekler ve{ ok: true, value }döner.keysatırı tanımlayan alanı adlandırır,eventspaketin kendi olay türlerini arayüzün onlarla yapacağı işe eşler (upsert,append,remove,refresh),maxarayüzün tutacağı satır sayısını sınırlar; çekirdek bu üçünü arayüze taşır, kendisi kullanmaz.commandsarayüzüncallExtensionile çalıştırdığı adlı fonksiyonlardır. Komut promise döndürebilir.capabilitiesher okuma ve çağrıda panel başına okunur:readreadExtensionSource'a,writecallExtension'a izin verir,subscribepaketin olaylarını geçirir. Yazılmayan alanfalse'tur. Red cevapları{ ok: false, error }biçimindenot allowed,no extension,no sourceya dano commandtaşır.sourcesvecommands'ta yalnız kendi anahtarlar bulunur;constructorve__proto__bulunmaz.emit(tür, yük)olayıext:<ad>:<tür>adıyla yayar; DevTools kapalıyken hiçbir şey yapmaz, kaydınpanels'ı varsa ve hiçbirindesubscribeyoksa da yapmaz.panels'sız kayıt eskisi gibi yayar.changed(kaynak?)arayüzün panelleri (argümansız) ya da o kaynağı yeniden okuması içinextension:changedyayar;reveal(hedef){ panel, route?, params?, state? }ileextension:revealyayar. İkisi de yalnız DevTools açıkken ve kayıt kendi adının güncel kaydıyken.pathOf(component)bileşenin DevTools yolunu verir.dispose()kaydı kaldırır veextension:disposedyayar. Aynı adla yapılan yeni kayıt eskisinin yerine geçer; eski kaydındispose()'u yenisini silmez. DevTools açıkken yapılan kayıtextension:registeredyayar.getExtensions()kayıtlı paketlerin adlarını listeler.
Çekirdeğin okumadığı her şey (id ve capabilities dışında panelin biçimi, key, events ve max'ın anlamı, reveal hedefinin içeriği) arayüzle paket arasındaki sözleşmedir; çekirdek olduğu gibi taşır.
Operation'lar ve yazma kayıtları
@motifx/core/devtools, bir paketin hangi işin neyi değiştirdiğini söyleyebilmesi için gerekeni de dışa verir: operation'lar ve yazma kayıtları. Geçmiş tutan, zaman çizelgesi çizen ya da bir değişikliği açıklayan paketler içindir; uygulama kodunun bunlara ihtiyacı yoktur.
Operation o an çalışan iştir: bir tıklama işleyicisi, bir gezinme, bir paketin aksiyonu. Çekirdeğin bir fonksiyon çalışırken tuttuğu tek bir değerdir, çalışan effect'i tuttuğu gibi. Uygulamaya ya da bileşen ağacına bağlı değildir, aşağıya aktarılmaz, bileşenler onu görmez. Yazmalar, flush tetikleyicileri ve operation olayları onun id'sini taşır.
import { runOperation, startOperation, resumeOperation, endOperation, currentOperation } from "@motifx/core/devtools";
runOperation({ kind: "action", name: "cart/add", data: { id: 7 } }, () => {
cart.items.push(item); // bu operation içinde yazıldı
});
await runOperation({ kind: "action", name: "orders/load" }, async () => {
const operation = currentOperation();
const rows = await api.orders();
resumeOperation(operation, () => { state.orders = rows; });
});
const operation = startOperation({ kind: "action", name: "chat/send" });
resumeOperation(operation, () => { state.sending = true; });
socket.onAnswer(() => resumeOperation(operation, () => {
state.sending = false;
endOperation(operation);
}));
startOperation(bilgi){ id, kind, name?, data?, parent? }verir.id'yi (artan bir sayı) veparent'ı (o anda çalışan operation) çekirdek verir;bilgiden başka hiçbir alan kopyalanmaz.kindpaketin seçtiği herhangi bir metindir.resumeOperation(operation, fn)fnçalışırken onu güncel operation yapar ve öncekini geri koyar;nullfn'i operation dışında çalıştırır. İstendiği kadar çağrılabilir.endOperation(operation, hata?)bir kez bitirir; sonraki çağrılar bir şey yapmaz. Bitmiş bir operation'ı yeniden sürdürmek yine onun altına kaydeder ve geliştirmede bir kez uyarır (MJX211).runOperation(bilgi, fn)üçünün tek çağrısıdır.fnpromise döndürürse operation promise sonuçlanınca biter verunOperationonu izleyen bir promise döndürür: aynı değer, aynı ret. DevTools kapalıykenfn'in sonucunu olduğu gibi döndürür.- JavaScript
awaitboyunca hiçbir değer taşımaz;await'ten sonra güncel operation yoktur, yukarıdaki kod onuresumeOperationile geri getirir.currentOperation()'ınawait'ten sonra ne verdiğine güvenmeyin. operation:startedoperation'ı,operation:finished{ id, duration, error? }taşır; ikisi de yalnız DevTools açıkken.startOperation,resumeOperationveendOperationüretimde de kalır; maliyetleri bir atamadır.
onWrite(fn) DevTools açıkken her reaktif yazmayı bildirir ve durduran bir fonksiyon döndürür. Her kaydın target'ı (ham nesne, dizi, Map, Set ya da signal) ve bir operation içindeyse operationId'si vardır:
kind |
Ne zaman | Alanlar |
|---|---|---|
add |
nesnede yeni anahtar, dizide sonun ötesinde bir indeks, Map'te yeni anahtar ya da Set'te yeni değer |
key, value |
update |
değişen değer: nesne anahtarı, dizi indeksi, uzayan length, Map değeri, signal.value (key: 'value') |
key, previous, value |
delete |
delete obj.key, map.delete(k), set.delete(v) |
key, previous |
clear |
map.clear(), set.clear() |
removed: map'in [key, value] çiftleri, set'in değerleri |
splice |
push, pop, shift, unshift, splice, sort, reverse, kısalan length |
method, index, removed, added |
mutate |
signal.mutate(fn); çekirdek fn'in neyi değiştirdiğini göremez |
– |
- Değerler saklandıkları gibi gelir: kopya değil, referans. Snapshot isteyen dinleyici kendisi alır.
- Hiçbir şeyi değiştirmeyen yazma (aynı değer yeniden, sırayı koruyan
sort) bildirilmez. Bir dizi metodu tek kayıttır; içinde yaptığı indeks yazmaları bildirilmez.items.length = 1kesilen öğelerimethod: 'length'ile birspliceolarak bildirir. - Birden fazla dinleyici kaydedilebilir; hata fırlatan atlanır. Dinleyicinin kendi yaptığı yazmalar bildirilmez; dinleyici kayıtlarını reaktif durumda tutabilir.
- Kayıtlar geliştirme içindir. Çekirdekteki her bildirim bir
@DEV-ONLYifadesidir, üretim derlemesi onları kaldırır; derleyicisiz kullanımda her biri DevTools kapalıyken false olan tek bir kontroldür. Uygulamanın ne yaptığının üretimdeki geçmişi uygulamanın kendisinindir: bir servis metodu ve tersi.
Sonraki adım
Dışa aktarılan bütün sembollerin özeti için API Referansı bölümüne geçin.