← Volver al Blog
Developer Tools

Persistencia en Tiptap: JSON, HTML y estado colaborativo

El JSON editable, el HTML renderizado y el estado colaborativo de Yjs resuelven problemas distintos de persistencia. Esta guía de Tiptap basada en la documentación explica cómo elegir una representación, comprobar la compatibilidad de las extensiones, restaurar de forma deliberada y planificar pruebas de las confirmaciones de guardado y las reconexiones.

Escrito por Hamza Diaz
13 de octubre de 202610 min de lectura41 vistas

Un producto hipotético de notas con asistencia de IA necesita volver a abrir notas editables. Más adelante, su equipo quiere publicar páginas legibles. La edición simultánea podría llegar después, pero es una decisión aparte. ¿Qué representación guardada corresponde a cada tarea?

Para Tiptap, empieza con JSON para el documento editable. Usa HTML cuando un consumidor necesite contenido renderizado o intercambio de contenido. Si el producto usa colaboración con Yjs, persiste su estado binario. Tratar estos formatos como copias de seguridad intercambiables deja demasiadas preguntas sin responder.

La pregunta más difícil es qué debe conservarse al volver a abrir un documento. Una nota puede verse bien y, aun así, perder una relación de la que depende tu producto. Esta guía de Tiptap 3.x usa una tabla de decisiones y la lista de comprobación 3R propuesta por Optijara para definir ese contrato. Las comprobaciones están pensadas para tu propio entorno; esta es una guía de decisiones basada en la documentación, sin ninguna instalación ni experimento de colaboración ejecutados.

Elige la representación que necesita tu producto

JSON para documentos editables, HTML para renderizado e intercambio

Tiptap recomienda la persistencia en JSON por su flexibilidad y facilidad de análisis. También permite hacer modificaciones externas sin otro analizador de HTML. Es posible guardar HTML. Sin embargo, su legibilidad dice poco sobre si el editor receptor puede restaurar fielmente el contenido.

Según la API de la instancia del editor, editor.getJSON() y editor.getHTML() devuelven el documento actual. JSON proporciona el árbol del documento. No captura la sesión completa del editor, incluida la selección o el historial de deshacer, y no puede sustituir el estado colaborativo. HTML tiene la misma separación entre documento y sesión.

RepresentaciónUso adecuadoCompatibilidad necesariaQué no conserva
JSON de TiptapAlmacenamiento de documentos editables y transformaciones estructuradasEsquema de extensiones del editor receptorEstado completo de ejecución, historial de deshacer o estado de Yjs
HTMLSalida renderizada o intercambio con un consumidor de HTMLExtensiones de análisis y renderizado, además de los requisitos del destinoFidelidad sin pérdidas al guardar y restaurar, ni una sesión del editor
Estado binario de YjsPersistencia de un documento colaborativo de YjsIntegración del documento colaborativo y el almacenamientoAutorización de la aplicación ni política de recuperación

Para renderizar sin un editor, comprueba la importación del paquete. La referencia de la utilidad HTML documenta que generateHTML de @tiptap/core solo funciona en el navegador. La versión de @tiptap/html admite tanto el servidor como el navegador. Ambas requieren las extensiones pertinentes. Revisa la seguridad de la salida por separado; la generación de HTML no ofrece una garantía general de saneamiento.

Estado binario de Yjs para la persistencia colaborativa

Usa la vía del estado binario descrita más abajo si la edición simultánea es un requisito. Para un producto de notas que solo necesita guardar y recargar, mantén el diseño más sencillo de almacenamiento de documentos. Un servidor de colaboración debe justificar su presencia con una necesidad del producto.

Trata el esquema de extensiones como parte del contrato del contenido guardado

Comprueba los nodos personalizados, las marcas y los documentos antiguos

La documentación del esquema de Tiptap describe un contrato construido a partir de las extensiones registradas. Esas extensiones determinan qué nodos y marcas están permitidos, junto con sus atributos y anidamiento. Un JSON válido puede contener una estructura que el editor receptor no pueda representar.

Volvamos al producto hipotético de notas. Supongamos que su equipo elimina una extensión de anotaciones personalizada, mientras que las notas antiguas aún contienen nodos de anotación. Alguien debe decidir qué ocurre con esas notas antes de cargarlas con la lista reducida de extensiones. Mantener la compatibilidad es una opción. En su lugar, podría ser apropiado aplicar una migración revisada o impedir la edición hasta completar la recuperación. Comparar el texto sin formato no detectaría la relación de la anotación.

Las notas de investigación requieren un cuidado similar. Decide qué identificadores de citas pertenecen a los atributos admitidos y qué relaciones con las fuentes necesitan registros separados en la aplicación. La guía de Zotero para notas de investigación que se pueden inspeccionar ayuda a identificar esas relaciones, sin especificar una integración con Tiptap. El texto renderizado de las referencias, por sí solo, es una base poco sólida para decidir qué conservar.

Entiende qué puede detectar la comprobación del contenido y qué no

En la referencia del esquema, enableContentCheck requiere activación explícita y su valor predeterminado es false. La comprobación de JSON es más rigurosa; la de HTML puede pasar por alto marcas no admitidas que después se eliminan. Incluye esa limitación en los criterios de aceptación de la restauración.

La gestión de la inicialización mediante onContentError difiere de la opción de comando errorOnInvalidContent. El patrón de gestión de errores de colaboración de la documentación usa disableCollaboration() para eliminar la extensión de colaboración. También usa editor.setEditable(false, false) para impedir la entrada sin emitir una actualización. Esto evita que se sincronice el contenido del que se han eliminado elementos, pero no puede reconstruir lo que se perdió.

Conserva los datos originales fuera del editor. Un schemaVersion gestionado por la aplicación, junto con reglas de migración revisadas, es una decisión de diseño útil. Tiptap no proporciona esa garantía de versionado de documentos. Conserva el original antes de aceptar cualquier sustitución transformada.

La guía 3R: Representación, Restauración, Recepción

3R es la lista de comprobación editorial propuesta por Optijara para la persistencia sin colaboración. No es una función oficial de Tiptap ni un método de despliegue validado. Úsala para plantear preguntas por separado sobre el contenido que almacenas y la forma de cargarlo. Después, establece qué se considera un guardado aceptado.

Representación: captura el documento que quieres persistir

Elige una representación de referencia y registra su configuración de extensiones compatible. Salvo que tu aplicación modele explícitamente los metadatos en el árbol de Tiptap, mantén la identidad del documento fuera de él. La versión del esquema y la revisión del backend también pertenecen al contrato de la aplicación. Una revisión de la aplicación tiene una función distinta de la de un atributo de nodo o una versión de paquete.

Para las notas creadas a partir de documentos extraídos, mantén la identidad de la fuente separada del texto editable. La guía de Docling sobre contenido estructurado y procedencia de las fuentes aborda ese límite de la ingesta previa. Úsala para decidir qué referencias a las fuentes necesitan las notas, en lugar de tomarla como una especificación de persistencia del editor.

Este JSON resume las decisiones propuestas en un formato legible por máquinas. Es un resumen editorial; no implica una solicitud de guardado ejecutable ni una prueba completada.

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

Restauración: sustituye el contenido de forma deliberada

La referencia del comando setContent indica que el comando sustituye el documento. En 3.x, el valor predeterminado de emitUpdate es true; en v2 era false. Consulta esta referencia del comando antes de copiar formas abreviadas de la página general de persistencia.

El siguiente ejemplo es ilustrativo y no se ha ejecutado. Presupone un editor de Tiptap 3.x ya existente con soporte para documentos y párrafos, además de texto. Sus datos corresponden a esa configuración. Aún tendrías que implementar el trabajo de red y base de datos.

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

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

Establecer emitUpdate: false puede evitar un guardado automático activado por una actualización al restaurar contenido. Aún hay que inspeccionar los demás manejadores de eventos de la aplicación, y el orden de las escrituras asíncronas sigue siendo tu responsabilidad. Si se rechaza la restauración, conserva los datos originales disponibles para la recuperación. No los sobrescribas con contenido aceptado parcialmente.

La referencia de eventos asigna significados distintos a estos eventos. update se refiere a cambios en el contenido. selectionUpdate se refiere a la selección, mientras que transaction abarca los cambios de estado de cualquier operación. Usa update o la función de devolución de llamada documentada onUpdate para guardar en respuesta a cambios de contenido, y comprueba qué hacen realmente tus otros manejadores de eventos.

Recepción: distingue las modificaciones locales de los guardados aceptados

Un indicador de guardado hace una promesa. Según este contrato de aplicación propuesto, debería significar que el backend aceptó la revisión correspondiente y que no hay ninguna modificación local más reciente pendiente. Serializar el contenido o iniciar una solicitud es demasiado pronto para hacer esa promesa.

Define cada transición antes de implementar este flujo de estados recomendado.

flowchart TD A[Modificación local sin guardar] --> B[Guardando la revisión capturada] B --> C{¿Revisión correspondiente aceptada?} C -->|Sí, sin modificaciones más recientes| D[Guardado] C -->|Sí, modificación más reciente pendiente| A C -->|Fallo o conflicto| E[Error o conflicto] E -->|Recuperación o reintento explícitos| A D -->|Nueva modificación| A

Una confirmación de una instantánea anterior debe dejar marcada como no guardada cualquier modificación más reciente. De lo contrario, la interfaz afirmaría la aceptación de un contenido que el backend no ha confirmado.

Usa comprobaciones de revisión esperada en el backend o elige otra política explícita de conflictos. La agrupación de eventos mediante un intervalo de espera ayuda a programar las solicitudes; no puede decidir qué revisión debería aceptar el servidor. Ante un fallo, conserva el contenido pendiente. Haz visible el conflicto y exige una recuperación deliberada antes de sustituir el trabajo local por una instantánea anterior confirmada. Estas decisiones corresponden a la aplicación, más allá de la API de eventos de Tiptap.

Mantén el estado colaborativo de Yjs separado de las proyecciones JSON

Persiste el estado binario, sin reconstruir el documento en cada reconexión

La documentación de persistencia de Hocuspocus exige almacenar el estado del documento codificado por Yjs como datos binarios Uint8Array. Su advertencia es concreta. Almacenar un Y.Doc como JSON y recrear el estado binario de Yjs cuando un usuario se conecta puede alterar la combinación de cambios y duplicar contenido en las nuevas conexiones.

Mantén JSON como proyección adicional si el producto la necesita. Persiste el estado colaborativo real para las reconexiones y conserva esa distinción en los procedimientos de copia de seguridad y restauración.

Hocuspocus documenta onStoreDocument para el almacenamiento y onLoadDocument para la carga. Las extensiones de base de datos ofrecen otra abstracción. Esas API identifican el límite de la persistencia; no constituyen una configuración completa del servidor. El flujo de guardado automático sin colaboración descrito antes es insuficiente para esta alternativa.

Decide si la colaboración es realmente necesaria

Si se añade colaboración más adelante, planifica explícitamente la conversión inicial. Conserva el original y prueba el comportamiento de reconexión en tu entorno antes de sustituir el formato de guardado existente. Un cambio silencioso de formato no ofrece criterios útiles de aceptación de la migración.

La persistencia del estado binario sigue dejando las decisiones de autorización y conservación en manos de la aplicación. Prueba las copias de seguridad de forma independiente. Revisa las migraciones de extensiones incluso después de una reconexión satisfactoria, porque volver a conectarse no demuestra la compatibilidad con un esquema modificado.

Errores de los equipos: una lista para comprobar el guardado y la restauración antes del lanzamiento

Prueba la fidelidad del contenido y el comportamiento de restauración

Las siguientes comprobaciones son pruebas propuestas para el lector. No se ejecutaron para este artículo. Crea datos sintéticos de prueba para el contenido que admite tu producto, registra la configuración de extensiones y conserva todos los datos originales. Compara los atributos relevantes además de la estructura. El texto visible es solo una parte del documento.

ErrorPrueba propuestaObservación esperada
Un JSON válido implica contenido fielGuardar y restaurar nodos personalizados, atributos, enlaces y marcasLa estructura y las relaciones admitidas permanecen intactas
Los documentos antiguos no necesitan una revisión de compatibilidadCargar un caso de prueba que requiera una extensión eliminadaRechazo explícito o migración revisada, conservando el original
Las actualizaciones al recargar son modificaciones del usuarioRestaurar con emitUpdate: false; inspeccionar los manejadores reales de guardadoNinguna escritura involuntaria activada por la restauración
La comprobación del contenido hace que el HTML sea seguroRevisar por separado las URL no confiables, los atributos y los contextos de salidaLas carencias de seguridad siguen siendo explícitas, sin quedar disfrazadas de comprobaciones de esquema superadas

Para el producto hipotético de notas, empieza con un caso de prueba de un párrafo sencillo. Añade una referencia enlazada y después una anotación personalizada con su relación esperada documentada. Incluye un caso de prueba de la configuración de esquema más antigua que se admita. Si cambia un atributo, investígalo aunque la nota restaurada parezca idéntica.

Usa la tabla como lista de comprobación de implementación y asigna un responsable a las observaciones pendientes de resolver. Una migración puede producir contenido válido y, al mismo tiempo, descartar una relación que necesita el producto. Ese resultado debería incumplir los criterios de aceptación del producto.

Prueba las condiciones de carrera del guardado y las reconexiones colaborativas

Retrasa y cambia el orden de las solicitudes de guardado en tu entorno de pruebas. Si la aplicación usa revisiones esperadas, verifica que se rechacen las escrituras obsoletas y que la interfaz informe de un conflicto. Confirma también que aceptar una instantánea anterior deje marcada como no guardada una modificación local posterior.

Con la colaboración activada, vuelve a conectar varios clientes al estado binario persistido. Inspecciona el resultado de la combinación de cambios y comprueba si hay duplicación. Registra las observaciones en lugar de suponer que el formato de almacenamiento documentado garantiza toda la integración.

La guía de Playwright para comprobar estados de la interfaz ofrece un enfoque relacionado para probar la interfaz. Adáptalo a los estados de guardado y recuperación y, después, añade una lectura de verificación desde el backend. Su caso de prueba de accesibilidad no comprueba la persistencia, y una etiqueta visible de guardado demuestra demasiado poco por sí sola.

Usa este plan de medición propuesto para conservar pruebas concretas. Define observaciones que recopilar, sin afirmar una puntuación de rendimiento ni un umbral de precisión.

PreguntaPruebas que registrarSiguiente paso
¿Se conservó el contenido?Estructuras originales y restauradas, configuración de extensionesInvestigar nodos o atributos que falten
¿Fue silenciosa la restauración, como se pretendía?Eventos observados y solicitudes de escritura resultantesCorregir los manejadores de eventos involuntarios
¿Qué guardado se aceptó?Revisión de la solicitud, confirmación del backend y lectura posterior de verificaciónResolver escrituras obsoletas y estados engañosos
¿Se reconectó correctamente la colaboración?Identidad del estado persistido y resultado observado de la combinación de cambiosInvestigar la duplicación antes del despliegue

Limitaciones y compromisos operativos

La validez del documento no equivale a seguridad ni durabilidad

La compatibilidad del esquema cubre un límite. La autorización del lado del servidor necesita su propia revisión, al igual que la validación de las solicitudes entrantes. Examina por separado la gestión del contenido privado y los contextos de salida no confiables. La política de conservación, las copias de seguridad y la recuperación tras escrituras fallidas también necesitan decisiones específicas de la aplicación. Esta guía no proporciona una auditoría de seguridad ni garantías de cumplimiento normativo.

Un renderizado HTML correcto no demuestra un ciclo de guardado y restauración sin pérdidas. Ten presente la limitación documentada de la comprobación, junto con la advertencia sobre el estado binario colaborativo. La serialización no puede proporcionar la política de conflictos del backend ni la durabilidad del almacenamiento.

Delimita con honestidad el trabajo de implementación

Las extensiones personalizadas implican trabajo de mantenimiento. Los documentos antiguos necesitan decisiones de migración, y la gestión de conflictos necesita implementación y pruebas. Añadir colaboración también significa operar su infraestructura. Prevé esas responsabilidades antes de elegir el diseño más complejo.

Esta guía no presenta ahorros medidos, mejoras de rendimiento ni resultados de despliegue. El fragmento de código sigue sin ejecutarse. Ejecuta las comprobaciones propuestas con tus propias dependencias y datos de prueba antes de afirmar que el comportamiento está verificado, y registra los resultados pendientes de resolver. Revisar la documentación te da una base para las pruebas; no equivale a una prueba superada de la aplicación.

Elige un contrato de persistencia y después prueba el ciclo de guardado y restauración

Identifica tu formato de guardado actual y la configuración de extensiones. Después, examina el comportamiento de restauración y qué considera la interfaz un guardado aceptado. Anota qué relaciones deben conservarse. Prueba un documento representativo, después un caso de prueba antiguo y un guardado fallido. Amplía la cobertura cuando comprendas esos resultados. Una nota que se renderiza correctamente es una observación inicial, no un motivo para dejar de probar.

Puntos clave

  • 1Elige JSON para documentos editables, HTML para renderizado o intercambio, y estado binario de Yjs persistido para la colaboración.
  • 2El JSON del documento no es una instantánea completa de la sesión del editor, del historial de deshacer ni del estado colaborativo.
  • 3Trata las extensiones configuradas como parte del contrato de restauración y conserva los datos originales durante las migraciones.
  • 4En Tiptap 3.x, setContent emite una actualización de forma predeterminada; suprímela deliberadamente al restaurar con guardado automático basado en actualizaciones.
  • 5Separa las modificaciones locales, las escrituras en curso y las confirmaciones del backend mediante una política explícita de conflictos.
  • 6Ejecuta comprobaciones de fidelidad del contenido, escrituras obsoletas, recuperación y reconexiones pertinentes en tu propio entorno antes de afirmar que la persistencia está verificada.

Conclusión

Empieza por la representación que necesita tu producto y haz explícito su contrato de extensiones. Usa 3R para revisar la restauración y la aceptación del guardado, y después prueba esas decisiones con tus propios datos de prueba y la política del backend. Si una nota pierde una relación o un indicador de guardado se adelanta al backend, resuelve esa carencia antes de añadir más funciones. Para obtener ayuda al delimitar una revisión de la persistencia del editor o de los límites de migración en un flujo de escritura con asistencia de IA, considera Optijara.

Preguntas frecuentes

¿Debo guardar el contenido de Tiptap como JSON o HTML? ¿Conserva JSON el historial del editor?

Usa JSON para una persistencia flexible de documentos editables, como recomienda Tiptap. Usa HTML para renderizar o intercambiar contenido con extensiones compatibles. `editor.getJSON()` devuelve el documento actual, no la sesión completa, la selección, el historial de deshacer ni el estado de Yjs. Ninguno de los formatos proporciona gestión de conflictos en el backend.

¿Cómo restauro el contenido de Tiptap sin activar un guardado automático basado en actualizaciones?

Usa `editor.commands.setContent(savedContent, { emitUpdate: false, errorOnInvalidContent: true })` con un editor compatible ya existente. En 3.x, el valor predeterminado de `emitUpdate` es `true`, a diferencia de v2. Suprimir esa actualización no detiene todos los manejadores de eventos de la aplicación ni todas las condiciones de carrera del guardado. Conserva los datos originales y gestiona explícitamente los errores de restauración.

¿Por qué pueden desaparecer nodos o marcas al cargar el contenido guardado?

Es posible que el esquema de extensiones del editor receptor no los admita. Revisa las extensiones que faltan y las migraciones, y conserva los datos originales. El valor predeterminado de `enableContentCheck` es `false`; la comprobación de HTML puede pasar por alto marcas no admitidas. La comprobación del contenido no es un motor de migración ni un mecanismo universal de recuperación.

¿Puedo generar HTML a partir del JSON de Tiptap en el servidor?

Sí. Usa la utilidad documentada `generateHTML` de `@tiptap/html` con las extensiones pertinentes para su uso en el servidor o el navegador. La variante de `@tiptap/core` solo funciona en el navegador. La generación de HTML no proporciona una garantía general de saneamiento; revisa por separado el contexto de salida y los valores no confiables.

¿Puedo persistir un documento colaborativo de Yjs como JSON?

No como sustituto del estado colaborativo. Hocuspocus exige datos binarios `Uint8Array` codificados por Yjs. JSON puede ser una proyección adicional, pero recrear un `Y.Doc` a partir de JSON al volver a conectarse puede alterar la combinación de cambios y duplicar el contenido. La autorización, las copias de seguridad y las migraciones del esquema siguen siendo responsabilidades separadas.

Fuentes

Compartir este artículo

Hamza Diaz

Escrito por

Hamza Diaz

Hamza Diaz es el fundador de Optijara, donde crea agentes de IA prácticos, sistemas de automatización y flujos de trabajo de Copilot para empresas de servicios. Escribe sobre operaciones de IA, estrategia de agentes e implementación real para equipos que quieren sistemas útiles en lugar de promesas vacías.