Xuda Slim

Le même runtime, 51 de ses 60 fichiers source, et un élément template dans votre page devient un programme.

Slim n'est ni une réécriture ni un portage. utils/bundle.js construit les deux bundles navigateur à partir du même arbre, dans la même exécution : le bundle complet concatène 60 fichiers source du runtime plus 9 fichiers fournisseurs, et Slim concatène 51 de ces mêmes fichiers runtime plus 2 fichiers fournisseurs, css.js et json5.min.js. Exactement 9 fichiers figurent dans la liste complète et sont absents de la liste Slim, et rien dans Slim n'est absent du bundle complet. Ces 9 fichiers sont xuda_actions.js, xuda_fcm_web.js et les sept fichiers du moteur de signal : xuda_reactive.core.js, .scheduler.js, .listdiff.js, .bridge.js, xuda_runtime.render.reactive.js, .adapter.js et .pilot.js. Une page Slim est donc dessinée par le moteur de rendu historique seul, sans moteur réactif en dessous. En échange, vous obtenez un chemin d'entrée sans étape de build : vous écrivez du HTML ordinaire dans un élément template, vous appelez xuda(), et le constructeur transforme chaque template de la page en programme identifié par son id. Deux précisions honnêtes avant la suite. Slim n'est pas léger en octets. Le module ES importé par les pages xuda.io pèse 671 803 octets sur disque et 143 551 en gzip niveau 9, et le fichier nommé xuda-runtime-slim.min.es.js n'est pas minifié : bundle.js écrit la chaîne concaténée telle quelle, sans jamais la faire passer par UglifyJS. Le nom décrit le chemin d'entrée et la liste des 51 fichiers source, pas le poids du téléchargement.

51 fichiers runtime, 2 fournisseurs tiers
L'id du template devient prog_id
Aucun moteur de signal, uniquement le moteur de rendu historique
Le même runtime, 51 de ses 60 fichiers source, et un élément template dans votre page devient un programme.
Balisage rédigé

Six fragments d'une page qui est versée dans ce dépôt.

Rien ici n'est une esquisse de ce à quoi la syntaxe pourrait ressembler. Chaque ligne ci-dessous est extraite de website-static/xuda.io/src/examples-html/index.html, la page sur laquelle le runtime est démontré, et les numéros de ligne sont indiqués pour que vous puissiez ouvrir le fichier et comparer. Lisez-la pour la forme plutôt que pour le style : un script module qui appelle le boot avec un prog id, un template dont l'id est ce prog id, xu-single-view comme racine, xu-store portant un état local avec xu-bind qui réécrit dedans, le trio xu-for qui parcourt un tableau en nommant à la fois l'index et la valeur, et xu-panel qui monte un second programme à l'intérieur du premier. Le préfixe xu-exp: sur un attribut signifie que la valeur est une expression plutôt qu'un littéral, et les expressions ici sont de l'eval : secure_eval compile une source dès sa deuxième occurrence avec new Function, et retombe sinon sur eval dans le scope propre de la page.

website-static/xuda.io/src/examples-html/index.html
lignes 29 à 55, le boot. Un appel, un prog id, aucun bundler dans la boucle
<script type="module">
import { bootTemplatePage } from "../assets/site.js";
bootTemplatePage({ progId: "xuda_slim_html_examples" });
lignes 79 et 80. L'id est le nom du programme, et l'id du premier template devient prog_id
<template id="xuda_slim_html_examples">
<xu-single-view>
lignes 194 à 197. État local, et une liaison bidirectionnelle dedans
<div xu-store="{'headline':'Bound by xu-bind'}">
<input xu-bind="headline" />
<p xu-exp:xu-content="@headline">Bound by xu-bind</p>
lignes 361 à 363. La boucle nomme l'index et la valeur, et les deux sont lisibles dans l'expression
<div xu-for="@steps" xu-for-key="stepIndex" xu-for-val="step">
<span xu-exp:xu-content="(@stepIndex + 1) + '. ' + @step.label">Label</span>
ligne 728. Un second programme, monté à sa place
<xu-panel program="child_panel_demo"></xu-panel>
Boot aux lignes 29 à 55, id du template à la 79, xu-single-view à la 80, xu-store avec xu-bind de 194 à 197, le trio xu-for de 361 à 363, xu-panel à la 728. Les attributs class sont retirés ici pour la largeur ; chaque attribut xu- est reproduit tel quel.
20

Gestionnaires d'attributs dans le registre de directives

6

Balises structurelles qu'un auteur est censé écrire

51

Fichiers source du runtime dans la liste Slim, sur 60

1084

Assertions réussies dans runtime/test, 0 échec

Le boot

Un seul constructeur, et trois façons mutuellement exclusives pour une page Slim de trouver ses programmes.

xuda() prend un élément, un objet d'options et un callback dans n'importe quel ordre, détectés par type plutôt que par position, et sous le bundle Slim, un élément manquant retombe sur le corps de la page en tant que chaîne, avec un avertissement, plutôt que d'annuler le boot. Ce qui se passe ensuite dépend d'une seule question, posée une seule fois : y a-t-il des éléments template sur la page. Les trois réponses ci-dessous ne se mélangent pas. La première réécrit la page, la deuxième la laisse intacte, et la troisième est le mode d'échec, et il vaut mieux savoir dans laquelle vous êtes avant de vous mettre à déboguer un écran blanc.

La branche template est destructive, et cela surprend : le balisage que vous avez écrit est analysé, converti, puis effacé de l'élément racine avant que le moteur de rendu ne le redessine. Si votre page contient du contenu rendu côté serveur en dehors du template, censé survivre au boot, vérifiez dans laquelle de ces trois branches vous vous trouvez réellement.
Slim face au complet

Neuf fichiers font toute la différence, et chacun est quelque chose qu'une page Slim ne peut pas faire.

Les deux bundles sont construits à partir du même arbre par le même script, utils/bundle.js. Slim concatène 51 fichiers source du runtime plus 2 fichiers fournisseurs. Le bundle navigateur complet concatène 60 fichiers runtime plus 9 fichiers fournisseurs. La comparaison des deux listes donne exactement 9 noms présents dans la liste complète et absents de la liste Slim, et rien dans Slim qui ne soit pas aussi dans le bundle complet. Slim est une soustraction, jamais une bifurcation, ce qui explique pourquoi une expression qui fonctionne dans l'un fonctionne dans l'autre. Suivent ces neuf noms et les quatre retours anticipés qui vont avec.

Slim
Bundle navigateur complet
Fichiers source du runtime51, concaténés à utils/bundle.js:243 et écrits directement sous forme de chaîne.60, à utils/bundle.js:62. Les neuf en plus sont xuda_actions.js, xuda_fcm_web.js et les sept fichiers du moteur réactif.
Fichiers fournisseurs2 : css.js et json5.min.js.9 : ces deux-là plus pouchdb.min.js, pouchdb.find.min.js, client.min.js, fingerprint2.min.js, socket.io.min.js, peerjs.min.js et clona-2.0.6.min.js.
Moteur de signalNon livré. xuda_reactive.core.js, .scheduler.js, .listdiff.js, .bridge.js et les trois fichiers render.reactive sont tous absents. Une page Slim est dessinée par le moteur de rendu historique seul.Livré : le moteur de rendu réactif, son scheduler, son diff de liste, et le pilot qui décide quel moteur de rendu un programme reçoit.
Adaptateur de base de donnéesJamais chargé. Le boot revient à runtime/js/index.js:407, avant le project loader et l'adaptateur aux lignes :423 à :429. func.db n'est jamais assigné et APP_OBJ[app_id] reste un objet vide.xuda-db-adapter-module.mjs est importé, func.db est assigné, et init_db_replication démarre sur l'app id.
Plugin de frameworkinit_ui_framework retourne dès sa première ligne quand glb.SLIM_BUNDLE est défini, à xuda_UI.utils.js:521. Les plugins de framework Tailwind et Ionic ne s'initialisent jamais.Le plugin de framework du programme est résolu et initialisé avant que l'arbre ne soit parcouru.
Plugins en arrière-planregister_run_background_plugins retourne de la même façon à xuda_main.js:199, si bien que rien ne s'exécute en arrière-plan.Parcourt app_plugins_purchased et démarre chaque entrée portant installed et run_in_background.
Source du programmeLe DOM. xuda() exécute document.querySelectorAll('template') à index.js:225, identifie chaque programme par son id ou par template_<index>, prend le premier id comme prog_id, puis vide l'élément racine. Un id manquant se termine sur console.error, xuda_utils.js:105 à 144._session.project_data.programs d'abord, et c'est seulement lorsque SLIM_BUNDLE n'est pas défini que la recherche se replie vers xuda-progs-loader-module.
Directives et expressions

Vingt gestionnaires d'attributs, et un ordre qui tient en deux tableaux.

Le registre de directives est un simple objet de 20 gestionnaires, de xu-attrs à la ligne 68 à xu-viewport à la ligne 234 de xuda_runtime.browser.handlers.factory.common.js. Un gestionnaire xu-exp supplémentaire est composé par-dessus, et des gestionnaires propres à certaines balises sont ajoutés pour xu-panel et xu-teleport. C'est tout le vocabulaire. Il n'y a ni étape de compilation ni langage de template : l'attribut est lu sur l'élément et la valeur est évaluée dans la page.

  • Les 20, dans l'ordre du code source : xu-attrs, xu-ref, xu-bind, xu-render, xu-show, xu-content, xu-text, xu-html, xu-for, xu-for-key, xu-for-val, xu-class, xu-on, xu-script, xu-style-global, xu-style, xu-cdn, xu-ui-plugin, xu-store, xu-viewport. Six balises structurelles sont aussi à votre disposition : xu-template, xu-single-view, xu-multi-view, xu-panel, xu-teleport, xu-slot. Deux autres, xu-nav et xu-modal-controller, sont internes, et le vérificateur du studio empêche de les rédiger.
  • xu-if, xu-else-if et xu-else sont natifs au moteur réactif uniquement. Pour le moteur de rendu historique, le seul dont Slim dispose, chaque branche est compilée en un xu-exp:xu-render équivalent à xuda_common.js:763 à 782, et les attributs xu-if rédigés sont délibérément laissés en place pour que le code source que vous avez écrit reste lisible dans le DOM.
  • xu-render et xu-if suppriment l'élément. Une porte fermée laisse derrière elle un élément xurender nu comme ancre pour repousser, à xuda_runtime.browser.dom.js:554. xu-show garde le nœud monté et bascule seulement la visibilité. Choisir entre les deux, c'est choisir si un sous-arbre caché vous coûte du DOM.
  • Les expressions sont de l'eval, et ce n'est pas une figure de style. secure_eval compile une source dès sa deuxième occurrence avec new Function('xu','func','glb','SESSION_ID','SESSION_OBJ','dsSessionP',...) à xuda_expression.js:1116, et retombe sinon sur eval(val) dans le scope de la page à :1134. Une Content Security Policy sans unsafe-eval ne peut exécuter un seul attribut xu-exp:.
L'ordre dans lequel un élément est évalué
  1. run_xu_before
    xu-cdn, xu-style, xu-render, xu-for-key, xu-for-val, dans cet ordre, de xuda_GLB.js:175 à 181. La porte et les clés de boucle sont réglées avant que quoi que ce soit ne les lise.
  2. Le corps
    Chaque gestionnaire restant, dans l'ordre où les attributs apparaissent sur l'élément. xu-for, xu-content, xu-show, xu-on et xu-store s'exécutent tous ici.
  3. run_xu_after
    xu-bind, xu-class, xu-script, xu-ui-plugin, xu-ref, de xuda_GLB.js:184. Le binding et les scripts voient un élément achevé, et xu-ref est distribué en dernier.
  4. La passe xu-exp
    xu-exp: n'est pas un 21e gestionnaire. Il est composé par-dessus le registre dans factory.js et marque la valeur comme une expression, si bien que xu-exp:xu-render occupe toujours la place de xu-render dans run_xu_before plutôt qu'une place propre.
Événements

Huit raccourcis, une réécriture, et aucun second système d'événements en dessous.

Huit abréviations d'événements sont déclarées dans un tableau unique, glb.attr_abbreviations_arr à xuda_GLB.js:185. Aucune n'est un gestionnaire. À la normalisation, xuda_runtime.browser.attributes.policy.js:42 à 56 vérifie si le nom de l'attribut figure dans ce tableau, écrit xu-on:<event> à sa place avec un gestionnaire personnalisé et un workflow d'exactement une étape de mise à jour, puis supprime l'attribut d'origine. xu-click et sa forme longue xu-on:click aboutissent au même code par le même chemin, ce qui explique qu'il n'y ait rien à apprendre sur les raccourcis au-delà de la liste des huit.

Mise en place

Importer le module, rédiger un template, appeler le constructeur.

Aucune étape de build, aucune configuration de bundler, aucune installation. Les pages d'exemples xuda.io font exactement ces trois choses et rien d'autre, ce qui en fait la référence honnête plutôt qu'un tutoriel rédigé après coup.

  1. 01

    Importer le module

    Le module ES importé par les pages xuda.io est website-static/xuda.io/src/assets/xuda-runtime-slim-es.js. Il pèse 671 803 octets sur disque et 143 551 en gzip niveau 9, et la copie dans l'arbre source et la copie dist construite sont identiques octet pour octet, md5 e950abcb5372188891ed775c62d55be4. Une précaution sur le nom : le fichier voisin appelé xuda-runtime-slim.min.es.js n'est pas minifié. bundle.js concatène les sources en une chaîne et l'écrit telle quelle à :312, sans passer par UglifyJS, et seule l'étape ultérieure vite plus terser du package npm minifie le module publié. Slim décrit la liste des 51 fichiers source et le chemin d'authoring, pas le poids du téléchargement.

  2. 02

    Donner à la page un template avec un id

    Un simple élément template HTML est aliasé sur xu-single-view dans chaque moteur de rendu, à xuda_runtime.browser.nodes.js:410 à 432. Cet alias est structurant : un véritable élément template est inerte par spécification, donc un chemin non aliasé appellerait createElement('template') et le programme n'afficherait rien. La page d'exemples ouvre le sien à website-static/xuda.io/src/examples-html/index.html:79, id de template xuda_slim_html_examples, avec xu-single-view à la ligne suivante. L'authoring HTML coûte un fetch réseau que l'authoring JSON n'a pas, car le scan de template importe dynamiquement xuda-cli-plugin-html-parser-module.esm.mjs, 748 lignes, à index.js:227, pour transformer le balisage en arbre de nœuds.

  3. 03

    Appeler le constructeur avec cet id

    website-static/xuda.io/src/assets/site.js:812 appelle new Xuda(document.getElementById(mountId) || document.body, {prog_id, ...}). xuda() prend un élément, un objet d'options et un callback dans n'importe quel ordre, détectés par type plutôt que par position, à runtime/js/index.js:41 à 60, et sous Slim, un élément manquant retombe sur 'body' avec un avertissement au lieu d'annuler le boot. Ensuite, le balisage fait le reste : xu-store avec xu-bind à index.html:194 à 197, le trio xu-for à 361 à 363, un xu-panel à 728. Une réserve avant de copier ce fichier : le module ES versé dans website-static est plus ancien que runtime/js. Une recherche n'y trouve ni xu-teleport, ni xu-attrs, ni xu-if, ni DS_LOADING, alors que la page d'exemples rédige xu-teleport sous un titre Live Preview.

Limites honnêtes

Neuf choses qu'une page Slim ne fait pas, chacune avec la ligne où en lire le refus.

  • Slim boote et retourne à la ligne 407 de runtime/js/index.js, avant le project loader à la 423 et l'adaptateur de base de données à la 425. func.db n'est jamais assigné et APP_OBJ[app_id] reste l'objet vide défini à la ligne 400, si bien qu'une page en drop-in n'a ni store PouchDB, ni réplication, ni registre de plugins.
  • xu-ui-plugin et xu-widget ne font rien sur une page Slim ordinaire. app_plugins_purchased n'est jamais peuplé, si bien que la première porte de run_ui_plugin, plugin?.installed à la ligne 2105 de runtime/js/xuda_common.js, est fausse à chaque appel. La page d'exemples xuda.io étiquette sa propre carte xu-ui-plugin Reference-only, à la ligne 674 de examples-html/index.html.
  • Ce n'est pas un bac à sable. secure_eval compile une source dès sa deuxième occurrence avec new Function à la ligne 1116 de runtime/js/xuda_expression.js, et retombe sinon sur eval(val) à la ligne 1134, et un plugin d'UI arrive par import dynamique dans le realm propre de la page, avec le nœud DOM brut en main. Une Content Security Policy sans unsafe-eval ne peut exécuter un seul attribut xu-exp:.
  • Les deux intégrations de framework sont désactivées plutôt que dégradées. init_ui_framework retourne dès la première ligne de son corps quand glb.SLIM_BUNDLE est défini, à la ligne 521 de runtime/js/xuda_UI.utils.js, et register_run_background_plugins fait de même à la ligne 199 de runtime/js/xuda_main.js. Tailwind et Ionic ne s'initialisent jamais sous Slim.
  • Le moteur de signal n'est pas dans la liste de fichiers. Les sept fichiers réactifs, xuda_reactive.core.js, .scheduler.js, .listdiff.js et .bridge.js plus xuda_runtime.render.reactive.js, .adapter.js et .pilot.js, se trouvent dans la liste complète aux lignes 131 à 138 de utils/bundle.js et dans aucune liste Slim. Une page Slim est dessinée par le moteur de rendu historique seul.
  • func.action est undefined, car xuda_actions.js fait partie des neuf fichiers que la liste Slim omet. L'étape de workflow invoke_action à la ligne 920 de runtime/js/xuda_events.js et le chemin realtime act_refresh à la ligne 107 de runtime/js/xuda_runtime.browser.realtime.js l'appellent tous les deux. Seul le second se trouve dans un catch.
  • Le module ES versé dans website-static/xuda.io est plus ancien que runtime/js. Une recherche de xu-teleport, xu-attrs, xu-if, DS_LOADING ou normalize_doc_for_runtime y donne zéro résultat pour chacun des cinq, alors que la page d'exemples rédige xu-teleport sous un titre Live Preview.
  • Slim n'est pas léger en octets. website-static/xuda.io/src/assets/xuda-runtime-slim-es.js pèse 671 803 octets sur disque et 143 551 en gzip niveau 9. Le nom décrit le chemin d'authoring et la liste des 51 fichiers source, pas le poids du téléchargement, et aucune comparaison de taille avec un autre framework n'est sourcée nulle part dans ce dépôt.
  • Deux des 29 suites de tests ne peuvent pas s'exécuter depuis un checkout propre. allprogs_sweep.mjs et realprog_dryrun.mjs lisent tous deux runtime/test/fixtures/progs, et runtime/test/fixtures ne contient qu'un .gitignore, si bien que les deux lèvent ENOENT avant de tester quoi que ce soit.
Regarder

La démonstration, après le mécanisme plutôt qu'à sa place.

Chaque affirmation ci-dessus a été relevée dans l'arbre le 2026-08-19 et porte le fichier et la ligne dont elle vient. Un enregistrement vidéo ne porte ni l'un ni l'autre, et un enregistrement vieillit. Donc, là où la vidéo et cette page divergent, la page l'emporte, et là où vous doutez de la page, ouvrez le fichier qu'elle cite. Regardez ceci pour la forme d'un drop-in, puis relisez l'encart pour ce que le drop-in ne fera pas.

Avant de le déployer

Les six questions que soulève la liste de fichiers

Répondu par rapport à l'arbre tel qu'il se présente le 2026-08-19, chacun avec le fichier et la ligne à vérifier.

Deux portes, une seule forme de project_data.

La porte du drop-in, c'est une balise script et un élément template. Sous Slim, xuda() exécute document.querySelectorAll("template"), transforme chaque résultat en programme identifié par son id ou par template_0, template_1 et ainsi de suite lorsqu'il n'en a pas, prend le premier id comme prog_id puis vide le innerHTML de l'élément racine, aux lignes 225 à 252 de runtime/js/index.js. Il prend aussi element, options et callback dans n'importe quel ordre, détectés par type plutôt que par position, et un élément manquant retombe sur body avec un avertissement au lieu d'annuler, aux lignes 41 à 60. L'authoring HTML coûte un fetch réseau que l'authoring JSON n'a pas : un import dynamique de xuda-cli-plugin-html-parser-module.esm.mjs à la ligne 227, 748 lignes, pour transformer votre balisage en arbre de nœuds. La porte du dashboard saute le scan et remet directement au runtime la même map de programmes, ce qui explique que les attributs appris ici se transposent intacts. Prenez la première si vous voulez une page. Prenez la seconde si vous voulez la base de données, la réplication et les 62 plugins que le boot Slim n'atteint jamais.