# « 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.

- Auteur : WordPress Développement
- Publié le : 2022-06-15
- Mis à jour le : 2022-06-15
- Catégorie : Blocs Gutenberg
- URL : https://www.wpmoderne.fr/blocs/erreur-maximum-call-stack-bloc-recursif/

## L’essentiel

- 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

« 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 ?
