Tiptap中,你可以将内容存为HTML格式,也可以存为JSON格式,哪种效率高呢?答案是后者。为什么呢?
For saving TipTap content, the JSON representation is overwhelmingly the best practice.
Let's break down why and clarify what "document" might mean in this context:
1. JSON (the output of editor.getJSON()) - BEST PRACTICE
-
What it is: This is the native, internal representation of your content in TipTap (which uses ProseMirror under the hood). It's a structured JSON object that describes the document's nodes, marks, and their attributes.
json{ "type": "doc", "content": [ { "type": "heading", "attrs": { "level": 1 }, "content": [ { "type": "text", "text": "My Awesome Document" } ] }, { "type": "paragraph", "content": [ { "type": "text", "text": "This is some " }, { "type": "text", "marks": [ { "type": "bold" } ], "text": "bold" }, { "type": "text", "text": " and " }, { "type": "text", "marks": [ { "type": "italic" } ], "text": "italic" }, { "type": "text", "text": " text." } ] } ] } -
Why it's best practice:
- Lossless: It perfectly preserves all semantic information, custom node types, custom attributes, and editor state. When you load this JSON back into TipTap, you get the exact same document you saved.
- Perfect Round-Trip: Essential for re-editing. You can reliably save, close, and re-open the editor with the exact previous state.
- Semantic Data: The structured JSON is more than just presentation; it describes the meaning and hierarchy of your content, which can be useful for other programmatic operations (e.g., searching, transformation, analysis).
- Often Smaller: For complex documents, the JSON can sometimes be more compact than the equivalent HTML.
- Source of Truth: It's the canonical representation of your content from TipTap's perspective.
-
When to use it: Always use this for your primary storage in a database or file system if you ever intend to re-load the content back into an editor for modification.
2. Rendered HTML (the output of editor.getHTML()) - NOT for Primary Storage
-
What it is: This is the HTML string generated by TipTap from its internal JSON representation, designed for display in a web browser.
html<h1>My Awesome Document</h1> <p>This is some <strong>bold</strong> and <em>italic</em> text.</p> -
Why it's generally NOT best practice for primary storage:
- Lossy: HTML primarily focuses on presentation. It often loses semantic information or specific attributes that might be present in your TipTap/ProseMirror JSON (especially if you have custom extensions). For example, a custom
CalloutBlockwith anidattribute might just become a<div>in HTML, losing its distinct type and ID. - Poor for Re-editing: While TipTap can parse HTML back into its editor, it's not a perfect round-trip. The editor has to "guess" how to map generic HTML tags back to its structured nodes and marks. This can lead to inconsistencies or loss of specific features when you re-import, particularly with custom extensions.
- Sanitization Required: If you store and then render user-generated HTML, you must sanitize it to prevent XSS (Cross-Site Scripting) vulnerabilities. This adds an extra layer of complexity and potential for errors.
- Lossy: HTML primarily focuses on presentation. It often loses semantic information or specific attributes that might be present in your TipTap/ProseMirror JSON (especially if you have custom extensions). For example, a custom
-
When you do need HTML:
- Display: You absolutely need HTML to display the content on a public webpage.
- SEO: Search engines consume HTML.
- Caching: You might cache the rendered HTML to avoid re-rendering every time content is requested.
Best Practice Recommendation: Store Both (but JSON is primary)
The most robust and flexible approach is often to store the JSON as your primary content source and generate/store HTML for display purposes.
Here's how that usually looks:
-
Database Storage:
- Create a column (e.g.,
content_json) in your database table (e.g.,posts,pages) to store the TipTap JSON. Use aTEXTorJSONB(PostgreSQL) type for this. - Optionally, create another column (e.g.,
content_html) to store the pre-rendered HTML. This saves you from converting JSON to HTML on every page load.
- Create a column (e.g.,
-
Saving Content:
- When the user saves their content in TipTap:
- Get the JSON:
const contentJson = editor.getJSON(); - Get the HTML:
const contentHtml = editor.getHTML(); - Important: Before saving
contentHtmlto the database or displaying it, always sanitize it using a library likeDOMPurifyto prevent XSS. - Save both
contentJsonandcontentHtmlto your database.
- Get the JSON:
- When the user saves their content in TipTap:
-
Loading Content for Editing:
- When you want to load content back into TipTap for editing:
- Fetch
content_jsonfrom your database. - Use
editor.setContent(contentJson, false);to load the content into the editor. (Thefalseflag tells it not to emit an update event immediately).
- Fetch
- When you want to load content back into TipTap for editing:
-
Loading Content for Display:
- When you want to display the content on a webpage:
- Fetch
content_htmlfrom your database. - Render it directly (since you've already sanitized it upon saving).
- Fetch
- When you want to display the content on a webpage:
Summary:
- For robust editing and future extensibility: Store JSON (
editor.getJSON()). This is the single source of truth for your TipTap content. - For displaying content on a webpage: Use HTML (
editor.getHTML()), but always sanitize it. - Ideal Workflow: Store both, with JSON as the primary, re-editable format, and HTML as a pre-rendered, sanitized version for efficient display.