Documentazione · src/engine/resolver
I resolver
Undici file, un contratto solo. Un blocco entra, esce un descrittore — o niente, che è una risposta legittima.
Il contratto: un descrittore, sempre lo stesso
Ogni resolver riceve (block, context) e restituisce la stessa forma: Component (chi disegna), ui (le props strutturali — classi, tag, attributi), slots (i figli già proiettati, per apertura), items (le righe, quando il blocco ne ha), data (tutto il dominio).
La separazione fra data e le chiavi strutturali non è ordine per l’ordine. È ciò che permette a un componente di essere scritto senza sapere quale blocco lo userà: legge da data quello che gli serve per nome, e le chiavi strutturali le consuma il primitivo comune. Mescolare le due cose — mettere il testo dentro ui — funzionerebbe per un componente e romperebbe la sostituibilità di tutti.
la forma del descrittore, e il tipo di una funzione resolver
Il descrittore, unica forma che il renderer sa disegnare
interface UIMSDescriptor {
Component?: any // assente per le composizioni, come `section`
ui?: UIMSUi // tag e props di sistema
slots?: Record<string, any>
items?: any[] // accordion, tabs, swiper: sotto-descrittori
data?: Record<string, any> // l'unico canale per i dati di dominio
}il registro: quale resolver per quale blockType
Il resolver di default fa quasi tutto
La maggior parte dei blocchi non ha un resolver proprio e passa da resolveViewMode: trova il viewMode per nome nel tema attivo (con fallback su uims), lo fonde con l’override del tema, ne ricava componente, classi, tag e slot, proietta i figli nelle aperture giuste e mette tutto il resto in data.
Un resolver dedicato serve solo quando il blocco ha bisogno di qualcosa che non è nel blocco stesso: un documento da dereferenziare, dei record da leggere, un form da iniettare. Sono i casi delle sezioni successive — sette in tutto su una trentina di tipi di blocco.
il default: viewMode → componente, classi, slot; il resto in data
Una sezione non è un componente
Una sezione è una composizione: sezione contiene contenitore contiene contenuto. Non ha un componente proprio, e infatti il suo descrittore non porta Component — è così che il renderer distingue le due cose senza un flag.
La conseguenza è che una sezione non si può disegnare «da sola»: è una struttura di tre livelli, ognuno con il suo viewMode e le sue classi. Ed è il motivo per cui i seeder del sito costruiscono le pagine con un helper sec({ section, container, content }) invece che con un blocco piatto.
la composizione a tre livelli; nessun Component
dereferenzia la sezione e restituisce ciò che il resolver di sopra ha prodotto
I riferimenti sono delega pura
Un blocco reference non ha una forma propria: punta a un documento, e ciò che va disegnato è quel documento con la forma che il suo resolver gli dà. Il resolver quindi non fa altro che risolvere il riferimento e restituire il descrittore altrui.
La lettura è deduplicata per richiesta e messa in cache con il tag del documento: dieci blocchi che puntano allo stesso record leggono una volta sola, e la modifica di quel record invalida esattamente quelle pagine. È il pezzo di DAL che rende sostenibile una pagina composta di riferimenti.
risolve il documento riferito e restituisce il suo descrittore
Le viste: una sezione con righe
Una vista è una sezione con righe: la tab Data della sezione dichiara cosa caricare, il suo container impagina, il contenuto ripete con repeatFor e legge con dataPathValue. Inline nel layout è usa e getta; come documento sections, citato da sectionRef, è riusabile. Con params e uno state diventa viva: il client chiede al server di rifare la sola sezione.
Un solo passo di binding per tutto: bindData espande le copie di repeatFor e legge i percorsi, dentro una copia relativi all’elemento; withOwnData carica le righe di una sezione e lega il suo contenuto.
La navigazione ha un caso a parte perché non ha bisogno di mappatura: le voci del menu arrivano già nella forma giusta e finiscono in data.navigation, che è quello che il componente legge.
le righe della sezione, il binding del contenuto, il wrapper vivo
carica le righe di un elemento e lega il suo contenuto
il passo di binding: repeatFor ripete, dataPathValue legge
le voci del menu in data.navigation
I form
Il blocco form è un contenitore con dentro il form riferito: i dati operativi (dove si invia, cosa si fa dopo) restano in data, gli input finiscono negli slot come figli. Il componente Form monta il contesto e i controlli si registrano da soli.
La forma dei singoli input viene dai viewMode come per qualunque altro blocco: un campo di testo si può ridisegnare senza toccare la logica di invio, che sta altrove.
il form riferito iniettato nel contenitore; dati operativi in data
Le reazioni risolte prima del client
Sull’istanza di un blocco si dichiara «quando succede X, fai Y»: un trigger e una conseguenza. La conseguenza spesso nomina una ricetta di animazione, che è un dato — vive nello store, non nel codice.
resolveReactions traduce quelle dichiarazioni nella forma che il nodo reattivo applicherà sul client, andando a prendere le ricette dal registro. Una reazione la cui ricetta non esiste viene lasciata cadere in silenzio: un’animazione mancante non è una ragione per non disegnare la pagina.
dalle dichiarazioni dell’istanza alla forma che applica UIMSReactive
Continua
Altro in «Il motore · src/engine»
La lettura del datoStili e classiTutte le diciassette pagineindice