WoodyLab
WoodyLabBuild with UIMS

Documentazione · @woodylab/uims

Il pacchetto

Dieci aree, e una regola che le tiene separate. Questa è la mappa: cosa contiene ogni cartella, cosa attraversa il confine verso il progetto che installa, e cosa resta dentro.

Dieci cartelle, ordinate per momento

Il sorgente non è diviso per tipo di file — non esiste una cartella `components/`, una `hooks/`, una `types/` — ma per il MOMENTO in cui una cosa entra in gioco nella vita di una pagina. Il dato viene letto, tradotto in descrittori, disegnato; la sua forma è decisa altrove e in anticipo; la configurazione la espone a chi scrive contenuto.

Il guadagno è pratico e si vede quando si aggiunge qualcosa: per sapere dove va un file nuovo non serve chiedersi che tipo di file è, serve chiedersi quando serve. Un resolver serve durante la risoluzione, quindi sta in `engine/resolver`; un componente serve durante il disegno, quindi sta in `react/components`. Non ci sono casi in cui la risposta è ambigua.

La regola sotto è una sola, e regge tutto il resto: `engine` non importa da `react`, e `react` non importa da `engine` se non i tipi. Il primo non sa che esiste un browser, il secondo non sa da dove viene il dato.

  • src/engine/ — legge il dato e lo traduce in descrittori. Gira sul server. Un terzo del volume di `react`
  • src/react/ — prende i descrittori e li disegna. L’area più grande: sessanta componenti più provider, stato ed eventi
  • src/config/ — la configurazione Payload: blocchi, campi, collection, global, hook. È la superficie che vede chi scrive contenuto
  • src/studio/ — l’editor dei viewMode, servito come vista dell’admin: è qui che si decide che aspetto ha una cosa
  • src/admin/ — la AdminBar — modificare il contenuto stando sopra il sito pubblico, non dentro un pannello
  • src/baselines/ — i valori di partenza da cui `init` scrive i sei store. Non sono runtime: il motore legge gli store, non questi file
  • src/plugin/ — il plugin Payload: il punto — l’unico — in cui il pacchetto entra in un progetto
  • src/cli/ — `woodylab-uims init`, che scaffolda il progetto ospite
  • src/utils/ — servizi: generazione delle CSS var, cache dei global, conversione colori, elenco icone
  • src/theme/ — le variabili complete di un tema: base ⊕ palette ⊕ font ⊕ override propri

Il confine: ventisei sottopercorsi, nessun wildcard

La `exports` del `package.json` elenca ventisei sottopercorsi, uno per uno. Un wildcard `./*` avrebbe risparmiato la manutenzione della lista e in cambio avrebbe reso pubblico ogni file interno: da quel momento qualunque riorganizzazione delle cartelle sarebbe stata un breaking change per chi ha installato, perché qualcuno avrebbe potuto importare da un percorso che noi consideravamo un dettaglio.

In repo però si consuma via `tsconfig.paths`, che il wildcard ce l’ha — ed è comodo mentre si sviluppa. Sviluppare e installare quindi non sono lo stesso percorso, e la differenza è esattamente il tipo di cosa che non dà nessun errore finché non la scopre chi installa. Per questo esistono due controlli: `check-package-paths.mjs` riconcilia le due liste, e `gate.sh` costruisce un progetto ex novo, installa il tarball, lancia `init` e compila. Il secondo è l’unico che esercita davvero il percorso pubblicato.

  • @woodylab/uims/config — blocchi, campi, collection, global: la configurazione Payload
  • @woodylab/uims/engine — contesto, contratto dei resolver, tipi, store tipizzati
  • @woodylab/uims/react — LayoutRenderer, componenti, provider, stato, eventi
  • @woodylab/uims/blocks — i costruttori di blocchi e i nodi Lexical: quello che usano i seeder
  • @woodylab/uims/dal — la lettura cache-aware delle collection
  • @woodylab/uims/admin — la AdminBar
  • @woodylab/uims/studio — lo Studio, più cinque punti d’aggancio (`/server`, `/next`, `/adminView`, `/StudioNavLink`, `/PublicSiteNavLink`)
  • @woodylab/uims/baselines — i dati di partenza, con un sottopercorso per store: `/themes`, `/palettes`, `/styles`, `/base-vars`, `/view-modes`, `/effects`, `/icons`
  • @woodylab/uims/plugin — il plugin Payload
  • @woodylab/uims/uims.md · /uims-workflow.md — i due documenti che il pacchetto spedisce per un assistente: le regole e l’ordine delle cose. Viaggiano in `dist/`, quindi li ha chiunque installi
  • @woodylab/uims/theme — le variabili complete di un tema
  • @woodylab/uims/utils — i servizi, più `/utils/generateCssVars` isolato perché lo usa il layout

Le due metà: risolvere e disegnare

Un blocco è dato: sta in database, lo scrive chi cura il contenuto. Un descrittore è ciò che il renderer sa disegnare. Fra i due c’è un solo passaggio, e avviene sul server: `UIMS.resolve(block)`.

Il descrittore ha sempre la stessa forma — `{ Component, ui, slots, items, data }` — e la separazione dentro di essa è la cosa che regge tutto: i dati di dominio stanno in `data` e in nessun’altra chiave. È per questo che un componente può non sapere niente del blocco che l’ha generato, e che lo stesso componente può disegnare blocchi diversi.

La conseguenza è la ragione per cui il pacchetto esiste: la forma è sostituibile senza toccare il dato. Cambiare il viewMode di un blocco cambia quale componente lo disegna, con che classi e con quali slot — e il contenuto non se ne accorge.

I sei store, e perché sono file

La forma non vive in database. Vive in sei file JSON alla radice del progetto ospite, importati staticamente: `db.viewmodes.json` (161 viewMode), `db.styles.json` (292 stili), `db.base-vars.json` (58 variabili), `db.themes.json` (13 temi), `db.animations.json` e `db.events.json`.

Due motivi, e nessuno dei due è la velocità in sé. Il primo: il percorso di render non fa una query per sapere che aspetto ha una card — se lo facesse, ogni pagina pagherebbe N letture per N blocchi, e il pacchetto ha già dovuto rimuovere una `payload.find` per ogni reazione proprio per questo. Il secondo, più decisivo: Tailwind può leggere un file con `@source` e generare le classi che ci trova. A un database non potrebbe. È da lì che nasce l’assenza di safelist.

Gli store li scrive `init` la prima volta, copiandoli dalle baseline del pacchetto, e da lì in poi appartengono al progetto: li modifica lo Studio, li si vede in un diff, li si mette in versione. Il pacchetto non li tocca più.

Cosa il pacchetto non fa, di proposito

Non legge `process.env`. I percorsi degli store li dichiara il consumer (`studio/paths.ts`); leggerli da variabili d’ambiente avrebbe significato che un nome scelto da noi diventava parte della configurazione di chi installa, e cambiarlo un breaking change invisibile.

Non installa i reducer. `UIStateProvider` non ha default: il motore è vuoto, e i reducer li mette il file `app-state.ts` che `init` scaffolda nel progetto — dove si vedono, si estendono e si possono togliere.

Non impone una palette né una tipografia. Le baseline sono un punto di partenza scritto una volta negli store del progetto; da lì in avanti è materiale del progetto.

Non registra i propri componenti come unica possibilità. `uimsComponents` è una mappa: il consumer la estende con la propria, e i viewMode che nominano un componente nuovo lo trovano.

Login