← Retour au Blog
Developer Tools

Persistance Tiptap : JSON, HTML et état collaboratif

Le JSON modifiable, le HTML rendu et l’état collaboratif Yjs répondent à des problèmes de persistance différents. Ce guide Tiptap fondé sur la documentation explique comment choisir une représentation, vérifier la compatibilité des extensions, restaurer de manière délibérée et planifier des tests des accusés de réception d’enregistrement et des reconnexions.

Rédigé par Hamza Diaz
13 octobre 202610 min de lecture42 vues

Un produit hypothétique de prise de notes assistée par l’IA doit permettre de rouvrir des notes modifiables. Plus tard, son équipe souhaite publier des pages lisibles. L’édition simultanée pourrait suivre, mais il s’agit d’une décision distincte. Quelle représentation enregistrée convient à chaque usage ?

Avec Tiptap, commencez par JSON pour le document modifiable. Utilisez HTML lorsqu’un système destinataire a besoin de contenu rendu ou d’un format d’échange. Si le produit utilise la collaboration Yjs, conservez son état binaire. Considérer ces formats comme des sauvegardes interchangeables laisse trop de questions sans réponse.

La question la plus délicate est de savoir ce qui doit subsister à la réouverture d’un document. Une note peut sembler correcte tout en perdant une relation dont votre produit dépend. Ce guide consacré à Tiptap 3.x utilise un tableau de décision et la liste de vérification 3R proposée par Optijara pour définir ce contrat. Les vérifications sont à effectuer dans votre propre environnement ; ce guide de décision s’appuie sur la documentation, sans installation ni expérience de collaboration exécutée.

Choisissez la représentation dont votre produit a besoin

JSON pour les documents modifiables, HTML pour le rendu et les échanges

Tiptap recommande la persistance en JSON pour sa souplesse et sa facilité d’analyse. Ce format permet également des modifications externes sans autre analyseur HTML. Enregistrer du HTML est possible. Sa lisibilité, toutefois, renseigne peu sur la capacité de l’éditeur destinataire à restaurer fidèlement le contenu.

Selon l’API de l’instance de l’éditeur, editor.getJSON() et editor.getHTML() renvoient le document actuel. JSON fournit l’arbre du document. Il ne capture pas la session complète de l’éditeur, notamment la sélection ou l’historique d’annulation, et ne peut pas remplacer l’état collaboratif. HTML présente la même limite entre document et session.

ReprésentationUsage appropriéCompatibilité requiseCe qu’elle ne préserve pas
JSON TiptapStockage de documents modifiables et transformations structuréesSchéma des extensions de l’éditeur destinataireÉtat d’exécution complet, historique d’annulation ou état Yjs
HTMLContenu rendu ou échange avec un système qui traite le HTMLExtensions d’analyse et de rendu, ainsi que les exigences du destinataireFidélité d’un aller-retour sans perte ou session de l’éditeur
État binaire YjsPersistance d’un document collaboratif YjsIntégration du document collaboratif et du stockageAutorisation dans l’application ou politique de récupération

Pour un rendu sans éditeur, vérifiez l’importation du paquet. La référence de l’utilitaire HTML indique que generateHTML de @tiptap/core est réservé au navigateur. La version de @tiptap/html fonctionne sur le serveur comme dans le navigateur. Toutes deux nécessitent les extensions appropriées. Examinez séparément la sécurité du contenu produit ; la génération HTML ne garantit pas un assainissement systématique.

L’état binaire Yjs pour la persistance collaborative

Utilisez le parcours fondé sur l’état binaire décrit ci-dessous si l’édition simultanée est une exigence. Pour un produit de prise de notes qui a seulement besoin d’enregistrer et de recharger les documents, conservez une conception plus simple de stockage des documents. Un serveur de collaboration doit répondre à un besoin du produit.

Intégrez le schéma des extensions au contrat du contenu enregistré

Vérifiez les nœuds personnalisés, les marques et les anciens documents

La documentation du schéma Tiptap décrit un contrat construit à partir des extensions enregistrées. Ces extensions déterminent les nœuds et les marques autorisés, ainsi que leurs attributs et leur imbrication. Un JSON valide peut tout de même contenir une structure que l’éditeur destinataire ne peut pas représenter.

Revenons au produit hypothétique de prise de notes. Supposons que son équipe supprime une extension d’annotation personnalisée, alors que les anciennes notes contiennent encore des nœuds d’annotation. Quelqu’un doit décider du traitement de ces notes avant leur chargement avec la liste réduite d’extensions. Maintenir leur prise en charge est une option. Une migration examinée ou un refus de modification dans l’attente d’une récupération peuvent aussi être appropriés. Une comparaison du texte brut ne détecterait pas la relation portée par l’annotation.

Les notes de recherche demandent une attention similaire. Déterminez quels identifiants de citation doivent figurer dans les attributs pris en charge et quelles relations avec les sources nécessitent des enregistrements distincts dans l’application. Le guide Zotero sur les notes de recherche vérifiables aide à identifier ces relations, sans définir une intégration Tiptap. Le texte rendu des références constitue à lui seul une base insuffisante pour décider de ce qu’il faut préserver.

Comprenez ce que la vérification du contenu peut détecter et ses limites

Dans la référence du schéma, enableContentCheck nécessite une activation explicite et vaut false par défaut. La vérification du JSON est plus complète ; celle du HTML peut manquer des marques non prises en charge qui sont ensuite supprimées. Tenez compte de cette limite dans les critères d’acceptation de la restauration.

La gestion à l’initialisation via onContentError diffère de l’option de commande errorOnInvalidContent. Le modèle de gestion des erreurs de collaboration présenté dans la documentation utilise disableCollaboration() pour retirer l’extension de collaboration. Il utilise également editor.setEditable(false, false) pour empêcher la saisie sans émettre de mise à jour. Cela empêche la synchronisation d’un contenu dont des éléments ont été supprimés, mais ne permet pas de reconstruire ce qui a été perdu.

Conservez les données d’origine en dehors de l’éditeur. Un schemaVersion géré par l’application, associé à des règles de migration examinées, constitue un choix de conception utile. Tiptap ne fournit pas cette garantie de gestion des versions des documents à votre place. Préservez la source avant d’accepter tout remplacement transformé.

La démarche 3R : Représentation, Restauration, Réception

3R est la liste de vérification éditoriale proposée par Optijara pour la persistance non collaborative. Il ne s’agit ni d’une fonctionnalité officielle de Tiptap ni d’une méthode de déploiement validée. Utilisez-la pour poser des questions distinctes sur le contenu stocké et sur son chargement. Définissez ensuite ce qui constitue un enregistrement accepté.

Représentation : capturez le document que vous souhaitez conserver

Choisissez une représentation faisant autorité et consignez la configuration d’extensions compatible. À moins que votre application ne modélise explicitement les métadonnées dans l’arbre Tiptap, conservez l’identité du document en dehors de cet arbre. La version du schéma et la révision du serveur font également partie du contrat de l’application. Une révision de l’application remplit un rôle différent de celui d’un attribut de nœud ou d’une version de paquet.

Pour les notes construites à partir de documents extraits, séparez l’identité de la source du texte modifiable. Le guide Docling sur le contenu structuré et la provenance des sources couvre cette frontière d’ingestion en amont. Utilisez-le pour déterminer les références aux sources dont les notes ont besoin, plutôt que comme une spécification de persistance de l’éditeur.

Ce JSON résume les choix proposés dans un format exploitable par une machine. Il s’agit d’une synthèse éditoriale, qui ne suppose aucune requête d’enregistrement exécutable ni aucun test effectué.

{
  "framework": "3r",
  "representation": "editable-json-compatible-extensions",
  "restore": "reject-incompatible-content-retain-original",
  "receipt": "acknowledge-applicable-backend-revision",
  "collaboration": "persist-yjs-binary-when-required"
}

Restauration : remplacez le contenu de manière délibérée

La référence de la commande setContent indique que cette commande remplace le document. Dans la version 3.x, emitUpdate vaut true par défaut ; dans la version 2, sa valeur par défaut était false. Consultez cette référence avant de copier une forme abrégée depuis la page générale sur la persistance.

L’exemple ci-dessous est illustratif et n’a pas été exécuté. Il suppose un editor Tiptap 3.x existant qui prend en charge les documents, les paragraphes et le texte. Ses données correspondent à cette configuration. Il vous resterait à mettre en œuvre les opérations réseau et de base de données.

const savedContent = {
  type: 'doc',
  content: [{
    type: 'paragraph',
    content: [{ type: 'text', text: 'saved-note' }],
  }],
}

editor.commands.setContent(savedContent, {
  emitUpdate: false,
  errorOnInvalidContent: true,
})

Définir emitUpdate: false peut éviter un enregistrement automatique déclenché par une mise à jour lors de la restauration du contenu. Il reste nécessaire d’examiner les autres écouteurs de l’application, et l’ordre des écritures asynchrones demeure votre responsabilité. Si la restauration est rejetée, gardez les données d’origine disponibles pour la récupération. Ne les écrasez pas avec un contenu partiellement accepté.

La référence des événements attribue des significations différentes à ces événements. update concerne les modifications du contenu. selectionUpdate concerne la sélection, tandis que transaction couvre les changements d’état issus de toute opération. Utilisez update ou la fonction de rappel documentée onUpdate pour les enregistrements déclenchés par des modifications du contenu, et vérifiez ce que font réellement vos autres écouteurs.

Réception : distinguez les modifications locales des enregistrements acceptés

Un indicateur d’enregistrement constitue une promesse. Dans le contrat d’application proposé ici, il devrait signifier que le serveur a accepté la révision concernée et qu’aucune modification locale plus récente n’est en attente. Sérialiser le contenu ou lancer une requête ne suffit pas encore à tenir cette promesse.

Définissez chaque transition avant de mettre en œuvre cet enchaînement d’états recommandé.

flowchart TD A[Modification locale non enregistrée] --> B[Enregistrement de la révision capturée] B --> C{Révision concernée acceptée ?} C -->|Oui, aucune modification plus récente| D[Enregistré] C -->|Oui, modification plus récente en attente| A C -->|Échec ou conflit| E[Erreur ou conflit] E -->|Récupération ou nouvelle tentative explicite| A D -->|Nouvelle modification| A

Un accusé de réception pour un instantané plus ancien doit laisser une modification plus récente indiquée comme non enregistrée. Sinon, l’interface annoncerait l’acceptation d’un contenu dont le serveur n’a pas accusé réception.

Utilisez des vérifications de la révision attendue côté serveur ou choisissez une autre politique explicite de gestion des conflits. La temporisation aide à planifier les requêtes ; elle ne peut pas décider de la révision que le serveur doit accepter. En cas d’échec, préservez le contenu en attente. Rendez le conflit visible et exigez une récupération délibérée avant de remplacer le travail local par un instantané plus ancien dont la réception a été confirmée. Ces décisions relèvent de l’application, au-delà de l’API d’événements de Tiptap.

Séparez l’état collaboratif Yjs des projections JSON

Conservez l’état binaire au lieu de reconstruire un document à chaque reconnexion

La documentation de persistance de Hocuspocus exige que l’état du document encodé par Yjs soit stocké sous forme de données binaires Uint8Array. Son avertissement est précis. Stocker un Y.Doc en JSON et recréer les données binaires Yjs lorsqu’un utilisateur se connecte peut perturber la fusion et dupliquer le contenu lors de nouvelles connexions.

Conservez le JSON comme projection supplémentaire si le produit en a besoin. Stockez l’état collaboratif réel pour les reconnexions et maintenez cette distinction dans les procédures de sauvegarde et de restauration.

Hocuspocus documente onStoreDocument pour le stockage et onLoadDocument pour le chargement. Les extensions de base de données offrent un autre niveau d’abstraction. Ces API définissent la frontière de persistance ; elles ne constituent pas une configuration complète du serveur. L’enchaînement d’enregistrement automatique non collaboratif présenté plus haut est insuffisant pour ce parcours.

Déterminez si la collaboration est réellement nécessaire

Si la collaboration est ajoutée ultérieurement, planifiez explicitement la conversion initiale. Conservez la source et testez le comportement de reconnexion dans votre environnement avant de remplacer le format d’enregistrement existant. Un changement silencieux de format ne vous donne aucun critère utile d’acceptation de la migration.

La persistance de l’état binaire laisse toujours à l’application les décisions d’autorisation et de conservation. Testez les sauvegardes indépendamment. Examinez les migrations d’extensions même après une reconnexion réussie, car une reconnexion ne démontre pas la compatibilité avec un schéma modifié.

Les erreurs des équipes : une liste de vérification des allers-retours avant la mise en production

Testez la fidélité du contenu et le comportement de restauration

Les vérifications suivantes sont des tests proposés au lecteur. Elles n’ont pas été exécutées pour cet article. Créez des jeux de données de test synthétiques pour le contenu pris en charge par votre produit, en consignant la configuration des extensions et en conservant toutes les données d’origine. Comparez les attributs significatifs ainsi que la structure. Le texte visible n’est qu’une partie du document.

ErreurTest proposéObservation attendue
Un JSON valide garantit un contenu fidèleEnregistrer et restaurer des nœuds personnalisés, des attributs, des liens et des marquesLa structure et les relations prises en charge restent intactes
Les anciens documents ne nécessitent aucun examen de compatibilitéCharger un jeu de données de test qui nécessite une extension suppriméeRejet explicite ou migration examinée, avec conservation de l’original
Les mises à jour au rechargement sont des modifications de l’utilisateurRestaurer avec emitUpdate: false ; examiner les écouteurs d’enregistrement réelsAucune écriture involontaire déclenchée par la restauration
La vérification du contenu rend le HTML sûrExaminer séparément les URL non fiables, les attributs et les contextes de sortieLes lacunes de sécurité restent explicites, sans être masquées par une validation du schéma

Pour le produit hypothétique de prise de notes, commencez par un jeu de données de test contenant un simple paragraphe. Ajoutez une référence liée, puis une annotation personnalisée dont vous aurez consigné la relation attendue. Incluez un jeu de données de test issu de la plus ancienne configuration de schéma prise en charge. Si un attribut change, cherchez-en la cause même lorsque la note restaurée semble identique.

Utilisez le tableau comme liste de vérification de mise en œuvre et désignez un responsable pour les observations non résolues. Une migration peut produire un contenu valide tout en supprimant une relation dont le produit a besoin. Ce résultat devrait échouer aux critères d’acceptation du produit.

Testez les conflits entre enregistrements et les reconnexions collaboratives

Retardez les requêtes d’enregistrement et modifiez leur ordre dans votre environnement de test. Si l’application utilise des révisions attendues, vérifiez que les écritures obsolètes sont rejetées et que l’interface signale un conflit. Confirmez également que l’acceptation d’un instantané antérieur laisse une modification locale ultérieure indiquée comme non enregistrée.

Avec la collaboration activée, reconnectez plusieurs clients à partir de l’état binaire conservé. Examinez le résultat de la fusion et vérifiez l’absence de duplication. Consignez les observations au lieu de supposer que le format de stockage documenté garantit l’ensemble de l’intégration.

Le guide Playwright sur la vérification des états de l’interface propose une approche connexe pour tester l’interface. Adaptez-la aux états d’enregistrement et de récupération, puis ajoutez une relecture des données côté serveur. Son jeu de données de test d’accessibilité ne teste pas la persistance, et un indicateur visible d’enregistrement ne prouve pas grand-chose à lui seul.

Utilisez ce plan de mesure proposé pour conserver des preuves concrètes. Il définit les observations à recueillir, sans prétendre fournir un score de performance ni un seuil de précision.

QuestionÉléments de preuve à consignerSuite à donner
Le contenu a-t-il été préservé ?Structures d’origine et restaurées, configuration des extensionsRechercher les causes des nœuds ou attributs manquants
La restauration s’est-elle déroulée sans événement de mise à jour, comme prévu ?Événements observés et requêtes d’écriture résultantesCorriger les écouteurs aux effets involontaires
Quel enregistrement a été accepté ?Révision de la requête, accusé de réception du serveur, relecture ultérieureRésoudre les écritures obsolètes et les états trompeurs
La reconnexion collaborative s’est-elle déroulée correctement ?Identité de l’état conservé et résultat de fusion observéRechercher les causes de duplication avant le déploiement

Limites et compromis opérationnels

La validité du document ne garantit ni la sécurité ni la durabilité

La compatibilité du schéma couvre une seule frontière. L’autorisation côté serveur nécessite son propre examen, tout comme la validation des requêtes entrantes. Examinez séparément le traitement du contenu privé et les contextes de sortie non fiables. La politique de conservation, les sauvegardes et la récupération après des écritures échouées nécessitent également des décisions propres à l’application. Ce guide ne fournit ni audit de sécurité ni assurance de conformité.

Un rendu HTML réussi ne démontre pas un aller-retour sans perte. Gardez à l’esprit la limite documentée de la vérification, ainsi que l’avertissement sur l’état binaire collaboratif. La sérialisation ne peut pas fournir la politique de gestion des conflits du serveur ni la durabilité du stockage.

Définissez honnêtement le périmètre de mise en œuvre

Les extensions personnalisées entraînent un travail de maintenance. Les anciens documents nécessitent des décisions de migration, et la gestion des conflits demande une mise en œuvre et des tests. Ajouter la collaboration implique également d’exploiter son infrastructure. Prévoyez les ressources nécessaires à ces responsabilités avant de choisir la conception la plus complexe.

Ce guide ne rapporte aucune économie mesurée, amélioration de performance ni résultat de déploiement. L’extrait de code n’a pas été exécuté. Effectuez les vérifications proposées avec vos propres dépendances et jeux de données de test avant d’affirmer que le comportement a été vérifié, et consignez les résultats non résolus. L’examen de la documentation fournit une base pour les tests ; ce n’est pas un test réussi de l’application.

Choisissez un contrat de persistance, puis testez l’aller-retour

Faites l’inventaire de votre format d’enregistrement actuel et de la configuration de vos extensions. Examinez ensuite le comportement de restauration et ce que l’interface considère comme un enregistrement accepté. Consignez les relations qui doivent être préservées. Testez un document représentatif, puis un ancien jeu de données de test et un échec d’enregistrement. Élargissez la couverture une fois ces résultats compris. Une note qui s’affiche correctement est une observation de départ, pas une raison d’arrêter les tests.

Points clés

  • 1Choisissez JSON pour les documents modifiables, HTML pour le rendu ou les échanges, et un état binaire Yjs conservé pour la collaboration.
  • 2Le JSON d’un document ne constitue pas un instantané complet de la session de l’éditeur, de l’historique d’annulation ou de l’état collaboratif.
  • 3Intégrez les extensions configurées au contrat de restauration et préservez les données d’origine pendant les migrations.
  • 4Dans Tiptap 3.x, setContent émet une mise à jour par défaut ; supprimez-la de manière délibérée lors d’une restauration si l’enregistrement automatique repose sur les mises à jour.
  • 5Distinguez les modifications locales, les écritures en cours et les accusés de réception du serveur dans le cadre d’une politique explicite de gestion des conflits.
  • 6Effectuez les vérifications de fidélité du contenu, d’écritures obsolètes, de récupération et, le cas échéant, de reconnexion dans votre propre environnement avant d’affirmer que la persistance a été vérifiée.

Conclusion

Commencez par la représentation dont votre produit a besoin et explicitez son contrat d’extensions. Utilisez 3R pour examiner la restauration et l’acceptation des enregistrements, puis testez ces décisions avec vos propres jeux de données de test et la politique de votre serveur. Si une note perd une relation ou si un indicateur d’enregistrement devance le serveur, corrigez cet écart avant d’ajouter des fonctionnalités. Pour obtenir de l’aide afin de définir le périmètre d’un examen de la persistance de l’éditeur ou des frontières de migration dans un processus d’écriture assistée par l’IA, vous pouvez faire appel à Optijara.

Questions fréquentes

Faut-il enregistrer le contenu Tiptap en JSON ou en HTML, et le JSON préserve-t-il l’historique de l’éditeur ?

Utilisez JSON pour une persistance souple des documents modifiables, comme le recommande Tiptap. Utilisez HTML pour le rendu ou les échanges avec des extensions compatibles. `editor.getJSON()` renvoie le document actuel, et non la session complète, la sélection, l’historique d’annulation ou l’état Yjs. Aucun des deux formats ne fournit la gestion des conflits côté serveur.

Comment restaurer le contenu Tiptap sans déclencher un enregistrement automatique fondé sur les mises à jour ?

Utilisez `editor.commands.setContent(savedContent, { emitUpdate: false, errorOnInvalidContent: true })` avec un éditeur compatible existant. Dans la version 3.x, `emitUpdate` vaut `true` par défaut, contrairement à la version 2. Supprimer cette mise à jour n’arrête pas tous les écouteurs de l’application ni tous les conflits entre enregistrements. Conservez les données d’origine et gérez explicitement les erreurs de restauration.

Pourquoi des nœuds ou des marques peuvent-ils disparaître lors du chargement d’un contenu enregistré ?

Le schéma des extensions de l’éditeur destinataire peut ne pas les prendre en charge. Examinez les extensions manquantes et les migrations, et préservez les données d’origine. `enableContentCheck` vaut `false` par défaut ; la vérification du HTML peut manquer des marques non prises en charge. La vérification du contenu n’est ni un moteur de migration ni un mécanisme universel de récupération.

Puis-je générer du HTML à partir du JSON Tiptap sur le serveur ?

Oui. Utilisez l’utilitaire documenté `generateHTML` de `@tiptap/html` avec les extensions appropriées, sur le serveur ou dans le navigateur. La variante de `@tiptap/core` est réservée au navigateur. La génération HTML ne garantit pas un assainissement systématique ; examinez séparément le contexte de sortie et les valeurs non fiables.

Puis-je conserver un document collaboratif Yjs en JSON ?

Pas en remplacement de l’état collaboratif. Hocuspocus exige des données binaires `Uint8Array` encodées par Yjs. Le JSON peut constituer une projection supplémentaire, mais recréer un `Y.Doc` à partir du JSON lors d’une reconnexion peut perturber la fusion et dupliquer le contenu. L’autorisation, les sauvegardes et les migrations de schéma restent des responsabilités distinctes.

Sources

Partager cet article

Hamza Diaz

Rédigé par

Hamza Diaz

Hamza Diaz est le fondateur d’Optijara, où il conçoit des agents IA pratiques, des systèmes d’automatisation et des workflows Copilot pour les entreprises de services. Il écrit sur les opérations IA, la stratégie d’agents et la mise en œuvre concrète pour les équipes qui veulent des systèmes utiles plutôt que du battage médiatique.