Aller au contenu
Server-driven UI : dix ans de leçons du mobileLecture : 0 %

Server-driven UI : dix ans de leçons du mobile

Faire décrire l'écran par le serveur contourne le cycle de publication mobile, au prix d'un catalogue de composants qui devient une API versionnée et d'un debug à trois dimensions. Où ça paie, comment ça dérive, et le critère pour s'arrêter.

Par Elias Varen7 min de lectureMembres

Le marketing veut inverser deux blocs sur l'écran d'accueil de l'application mobile avant la campagne de jeudi. Sur le web, c'est un déploiement de dix minutes. Sur mobile, il faut une version à compiler, à soumettre, à faire valider, puis à faire installer, et jeudi soir un tiers des utilisateurs aura encore l'ancien ordre.

La réponse que le mobile a mise au point au fil des années tient en une phrase : l'application ne sait plus à quoi ressemble l'écran, elle sait seulement dessiner des briques, et c'est le serveur qui lui dit lesquelles, dans quel ordre, avec quelles données. Inverser deux blocs redevient un changement côté serveur, effectif partout dans la minute.

L'idée est bonne. Elle déplace pourtant un problème plus qu'elle ne le supprime, et la plupart des équipes qui s'y lancent découvrent ce déplacement trop tard.

Un registre de blocs et un arbre typé

Le serveur renvoie une description d'écran, c'est-à-dire un arbre de nœuds typés.

JSON
{
  "ecran": "accueil",
  "disposition": "acc-2026-10-a",
  "blocs": [
    { "type": "banniere", "v": 2, "titre": "Livraison offerte", "image": "…", "action": { "type": "ouvrir", "cible": "promo/automne" } },
    { "type": "carrousel_produits", "v": 1, "source": "nouveautes", "elements": [] },
    { "type": "compte_a_rebours", "v": 1, "fin": "2026-10-08T22:00:00Z",
      "repli": { "type": "texte", "v": 1, "contenu": "Offre jusqu'au 8 octobre" } }
  ]
}

Le client tient un registre qui associe chaque type à un composant natif :

TypeScript
type Bloc = { type: string; v: number; repli?: Bloc } & Record<string, unknown>;

const registre: Record<string, { vMax: number; rendre: (b: Bloc) => Vue }> = {
  banniere: { vMax: 2, rendre: rendreBanniere },
  carrousel_produits: { vMax: 1, rendre: rendreCarrousel },
  texte: { vMax: 1, rendre: rendreTexte },
};

function rendre(bloc: Bloc): Vue | null {
  const entree = registre[bloc.type];
  if (entree && bloc.v <= entree.vMax) return entree.rendre(bloc);
  if (bloc.repli) return rendre(bloc.repli);
  signalerBlocInconnu(bloc.type, bloc.v);
  return null;
}

Tout est déjà là : un type que le client ne connaît pas (compte_a_rebours pour une application publiée avant sa création), une version de bloc trop récente, un repli. L'essentiel du sujet tient dans ces trois lignes de la fonction rendre.

Le catalogue vieillit comme une API publique

On voulait échapper au cycle de publication. On y échappe pour l'agencement des briques, mais on y reste soumis pour les briques elles-mêmes, puisqu'un nouveau composant n'existe que dans les versions compilées après sa création.