Mardi dernier, Mira, qui gère la partie frontend de notre panneau d'admin Inertia, m'a envoyé un enregistrement d'écran. Elle ouvre l'aperçu d'export des factures, qui met un moment à se construire parce qu'il affiche environ onze mille lignes de tableau. Puis elle tape un nom de client dans la recherche de la barre latérale, et les résultats restent là, figés, jusqu'à ce que l'aperçu d'export ait fini. « Pourquoi la recherche se soucie-t-elle de l'export ? » m'a-t-elle écrit. Bonne question. Côté PHP, on a arrêté de se la poser il y a longtemps, parce que notre runtime y a répondu pour nous.
Pense à ce que fait vraiment un pool PHP-FPM. Un worker reste coincé sur une requête SQL de 9 secondes pour un rapport, et la requête HTTP suivante part vers un autre worker, fait son travail et répond en 40 ms sans jamais apprendre que le rapport existe. Le shared-nothing est une habitude qu'on ne remarque même plus. Chaque requête vit et meurt seule, donc une requête lente ne peut pas faire paraître lente une requête qui n'a rien à voir. D'après ce que je comprends des changements de React 19.3, le côté client adopte maintenant cette même habitude pour les transitions, et je pense que c'est le bon choix. Ça fait aussi du frontend un terrain plus naturel pour les gens qui pensent en PHP.
Voici les faits. Une transition, c'est tout ce que tu enveloppes dans startTransition(), et elle indique à React que la mise à jour est réelle mais peut céder la place à tout ce qui est urgent, comme une frappe au clavier. Avant 19.3, si deux transitions étaient en cours en même temps, React pouvait les lier, si bien que la moins coûteuse finissait par attendre que la plus lourde ait terminé. Avec 19.3, des transitions qui n'ont rien à voir entre elles peuvent se rendre indépendamment. La recherche et l'aperçu d'export de Mira deviennent deux workers FPM au lieu d'un seul worker avec une longue file d'attente derrière lui. L'article qui m'a mis sur la piste précise prudemment que le gain dépend de ce que tu rends et de la question de savoir si les mises à jour se touchent vraiment, et je le souligne volontiers.
Il y a une objection solide ici, et je veux la prendre au sérieux. Rien de tout ça ne rend quoi que ce soit plus rapide. Un composant qui a besoin de 400 ms pour se rendre a toujours besoin de 400 ms. Tout ce que React change, c'est le moment où ce temps est dépensé et ce qui a le droit de passer devant. Un sceptique dirait qu'un ordonnancement plus malin est un excellent moyen de cacher un composant obèse, comme un gros pool FPM te permet d'ignorer une requête SQL catastrophique jusqu'à ce que la base de données tombe en fin de mois. J'ai vécu cette fin de mois. Le pool a permis au site de continuer à répondre, et il a aussi dispensé tout le monde de corriger la requête pendant deux ans.
Alors oui, l'isolation peut devenir une excuse. Je finis quand même par m'en réjouir, parce que l'alternative est pire. Quand tout est couplé, l'utilisateur paie pour ton code le plus lent à chaque interaction, y compris celles qui ne l'ont jamais touché. Avec l'isolation, il ne paie que pour ce qu'il a réellement demandé. C'est un meilleur comportement par défaut, et ça ne t'empêche pas de profiler. Au contraire, ça rend le profilage plus honnête : une fois que l'aperçu d'export n'entraîne plus la recherche dans sa chute, ses 400 ms apparaissent dans le profiler comme son propre coût au lieu de se cacher dans les chiffres de tout le reste.
Ce que j'en retiens en tant que dev backend tient moins aux API de React qu'à la forme de nos réponses. L'aperçu d'export et la recherche de Mira appellent tous les deux des endpoints Laravel. Si ces deux endpoints partagent un verrou de session, ou si un énorme payload de props est reconstruit à chaque visite Inertia, le client peut ordonnancer aussi intelligemment qu'il veut, les deux tâches resteront liées côté serveur. L'indépendance doit exister jusqu'en bas de la pile pour que l'ordonnanceur puisse en faire quelque chose. On sait déjà donner à chaque morceau de l'UI son propre endpoint léger, avec des rechargements partiels, des routes séparées et aucune écriture de session sur les appels en lecture seule. Maintenant, il y a une récompense concrète à le faire.
Soyons justes, les transitions n'ont jamais été faites pour tout. Un input contrôlé doit toujours se mettre à jour immédiatement, et le schéma habituel tient toujours : garde la valeur que tu tapes en urgent et ne pousse que l'état dérivé coûteux dans startTransition(). Ça n'a pas changé. La nouveauté, c'est que tu peux maintenant faire tourner plusieurs de ces mises à jour en arrière-plan sans qu'elles te reviennent sous la forme d'un seul gros bloc lent.
Là où j'ai un vrai doute, c'est sur la dynamique d'équipe. Chez nous, la personne qui écrit l'endpoint est rarement celle qui enveloppe la mise à jour dans startTransition(), et l'isolation d'un côté ne paie que si l'autre côté coopère. Alors, toi qui livres des backends PHP pour des frontends React : quand l'UI commence à ramer, qui est responsable du correctif dans ton équipe, et est-ce qu'un changement comme 19.3 a déjà déplacé cette frontière ?




Commentaires
Pas encore de commentaire — écris le premier.
Lance la discussion
Pas de compte ni de mot de passe — saisis simplement ton adresse e-mail et nous t’envoyons un lien de connexion à usage unique. Première visite ? Tout se met en place automatiquement.
Ton évaluation sera appliquée automatiquement après ta connexion.
Vérifie ta boîte mail
Nous avons envoyé un lien de connexion à …. Ouvre-le sur cet appareil — cet onglet te connectera automatiquement.
Rien reçu ? Vérifiez le dossier spam — et marquez le message « Non spam » pour qu'il arrive directement la prochaine fois.