Le WordPress d'aujourd'hui, décodé pour les développeurs

Blocs Gutenberg

« Maximum call stack size exceeded » dans un bloc récursif mal conçu

Diagnostic d'un template InnerBlocks qui s'auto-référence et bloque l'éditeur, avec le correctif de structure qui met fin à la boucle infinie.

Par WordPress Développement • 15 juin 2022 • 4 min de lecture • Aucun commentaire
« Maximum call stack size exceeded » dans un bloc récursif mal conçu

« Maximum call stack size exceeded » s’affiche dans la console juste avant que l’onglet ne cesse complètement de répondre. L’article qui déclenche ce plantage contient un unique bloc conteneur, en apparence anodin, dont le template d’InnerBlocks se référence lui-même sans que personne ne s’en soit rendu compte au moment du développement.

Ce type d’erreur survient rarement en usage normal : elle apparaît généralement après une modification du template par défaut d’un bloc conteneur, quand un développeur ajoute une nouvelle section sans vérifier que le nom de bloc utilisé ne correspond pas, par erreur, au bloc conteneur lui-même.

Comprendre le mécanisme du template récursif

Un bloc conteneur personnalisé peut définir un template par défaut, qui pré-remplit automatiquement les blocs enfants à l’insertion. Ce template accepte une liste de couples [ nom-du-bloc, attributs, template-enfant ] :

const TEMPLATE = [
    [ 'wpmoderne/section-conteneur', {}, [
        [ 'core/paragraph', { placeholder: 'Texte de la section' } ],
    ] ],
];

registerBlockType( 'wpmoderne/section-conteneur', {
    edit: ( { attributes } ) => (
        <InnerBlocks template={ TEMPLATE } />
    ),
} );

L’erreur, ici, saute rapidement aux yeux une fois isolée : le bloc wpmoderne/section-conteneur inclut, dans son propre template, une instance de lui-même. Chaque insertion du bloc tente de générer un enfant identique, qui tente à son tour de générer un enfant identique, sans condition d’arrêt.

L'essentiel à retenir : Le navigateur plante avant même d'afficher un message clair ; Un template InnerBlocks peut s'insérer lui-même par erreur ; La correction passe par une restriction explicite des blocs autorisés

Pourquoi ce genre d’erreur passe inaperçu en développement

Le bug ne s’est manifesté qu’après un renommage de bloc effectué en fin de sprint, où un ancien bloc wpmoderne/section a été renommé en wpmoderne/section-conteneur pour plus de clarté, sans que le template interne de ce même bloc ne soit mis à jour en conséquence. Le renommage a créé la référence circulaire sans qu’aucune erreur ne se déclenche au moment du renommage lui-même, seulement à la prochaine insertion du bloc.

Corriger la structure

Le correctif consiste à référencer le bon bloc enfant, différent du conteneur, dans le template :

const TEMPLATE = [
    [ 'wpmoderne/bloc-texte-section', {}, [
        [ 'core/paragraph', { placeholder: 'Texte de la section' } ],
    ] ],
];

Une vérification supplémentaire, utile pour prévenir toute récidive future, consiste à restreindre explicitement les blocs autorisés en enfant via l’attribut allowedBlocks d’InnerBlocks, ce qui empêche structurellement toute auto-référence, même accidentelle :

<InnerBlocks
    template={ TEMPLATE }
    allowedBlocks={ [ 'wpmoderne/bloc-texte-section', 'core/paragraph', 'core/image' ] }
/>

Prévenir plutôt que déboguer après coup

  • Toujours définir allowedBlocks sur un conteneur personnalisé, plutôt que d’autoriser tous les blocs par défaut.
  • Après tout renommage de bloc, rechercher son ancien nom et son nouveau nom dans l’ensemble du projet, y compris dans les templates d’autres blocs qui pourraient y faire référence.
  • Ajouter un test automatisé simple qui insère chaque bloc conteneur du projet dans un environnement de test et vérifie que le rendu se termine sans dépassement de pile.

Ce que cet article ne couvre pas

Les transforms de blocs, qui permettent de convertir un bloc en un autre à la demande de l’utilisateur, suivent une logique complètement différente et ne présentent pas ce risque de récursion involontaire de la même manière. Le contexte de bloc parent-enfant classique, utilisé pour partager des données entre un conteneur et ses enfants sans passer par un template, mérite également un traitement séparé, plus large que ce cas de débogage précis.

Prévention

Un plantage par dépassement de pile d’appels ne laisse quasiment jamais de message exploitable directement : il faut reconstruire mentalement la chaîne d’appels pour comprendre où la boucle se ferme. Sur un bloc conteneur, la première hypothèse à vérifier reste presque toujours la même : le template fait-il référence, directement ou indirectement, au bloc qui le contient ?

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi