If you are working with tiptap v.1 and want to upgrade to tiptap v.2 here is the story of how I did it for my project LoreHub.
LoreHub's stack
Back - .net 6, ef 6, c#
Front - Vue.js 2, Veutify, Pinia 
Initial setup
I have a Vue.js component that does a put request that will update the description on the server. It will do two things:
- Updates in the description's snapshot table.
- Insert into the description's history table.
Here are parts from the Vue component. As you can see I initialize the editor and on an update, it fires debounce function. Debounce function allows it to do requests only if the user will stop updating the content for 3 seconds. The debounce function is from lodash.
import debounce from "lodash-es/debounce";
function initEditor () {
    this.editor = new Editor({
        extensions: [
          // extensions
        ],
        onUpdate: ({ getJSON }) => {
          this.content = getJSON();
          this.isSaving = true;
          this.updateDocumentDescriptionOnServerDebounce();
        },
    });
}
function updateDocumentDescriptionOnServerDebounce: debounce(async function () {
    await this.updateDocumentDescriptionOnServer();
}, 3000),
async updateDocumentDescriptionOnServer() {
    try {
        this.serverError = null;
        // pinia store action - put to WebApi
        await useDescriptionStore().updateDescription(
          this.settingId,
          this.type,
          this.forId,
          this.content
        );
        this.isSavingValue = false;
      } catch (e) {
        // some error handling
        this.serverError = e;
        this.isSavingValue = false;
      }
}
Time to upgrade
First of all, I do everything that is mentioned in the official upgrade guide - https://tiptap.dev/overview/upgrade-guide
So it took some time, but then I face a problem that requires me to migrate standard extensions names. Imagine I have gigabytes of data in my database that contains JSONs and I need to iterate through all of this to rename extensions types. It is not an option and there should be a better way to do it.
How do I solve it? My idea was to create a migration function that will do it on the front end. But I don't want it to run every time the description is loaded. The solution will be to save the state in the database that the migration was performed and I don't want it to do it again.
I decided to change my WebAPI and database. I introduce a new column 'EditorVersion'. Because I have too many raws to update I set this field as nullable, without a default value.
Example entity framework migration:
// ef 6 migration
migrationBuilder.AddColumn<string>(
    name: "EditorVersion",
    table: "Descriptions_History",
    type: "nvarchar(max)",
    nullable: true);
migrationBuilder.AddColumn<string>(
    name: "EditorVersion",
    table: "Descriptions_Description",
    type: "nvarchar(max)",
    nullable: true);
After this I've created a v2 description.get action on the back that returns not just JSON, but JSON and editorVersion.
Description {
    value   string
    nullable: true
    editorVersion   string
    nullable: true
}
If editorVersion is null it will run this migration on the front:
migrateExtensions(content) {
      for (const node of content) {
        // tiptap 2 migrate extensions type from v.1 to v2.
        // https://tiptap.dev/overview/upgrade-guide#new-names-for-most-extensions
        if (node.type === "bullet_list") node.type = "bulletList";
        if (node.type === "code_block") node.type = "codeBlock";
        if (node.type === "hard_break") node.type = "hardBreak";
        if (node.type === "horizontal_rule") node.type = "horizontalRule";
        if (node.type === "list_item") node.type = "listItem";
        if (node.type === "ordered_list") node.type = "orderedList";
        if (node.type === "table_cell") node.type = "tableCell";
        if (node.type === "table_header") node.type = "tableHeader";
        if (node.type === "table_row") node.type = "tableRow";
        if (node.type === "todo_list") node.type = "taskList";
        if (node.type === "todo_item") node.type = "todo_item";
        // recursion
        if (node.content && node.content.length > 0)
          migrateExtensions(node.content);
      }
    }
After the migration is done it will perform put request that will send updated JSON and set editor version to 'tiptap_v2'.
Conclusion
It took me about three days of work to migrate from tiptap v1 to tiptap v2. It includes migration for a custom extension that uses a Vue router for links. The tiptap's team did a good job with the migration guide, thank you. It was straightforward and easy to do.
Overall I like the new tiptap's API and this little hack allows to do a lazy migration 😊.
I hope this guide will help you do the migration and if you have any questions feel free to ask.
 


 
    
Top comments (0)