NextJS struggles to load EditorJS plugins

I am currently working on integrating EditorJS into my NextJS project. The editor is loading properly without any plugins, with only paragraph as a block option. However, I'm facing an issue when trying to add plugins using the tools prop which results in the following warning being thrown in the console:

editor.js?9336:2 Module Tools was skipped because of TypeError: Cannot read property 'prepare' of undefined

Furthermore, upon clicking on the editor in the browser, another error is thrown:

Uncaught TypeError: Cannot read property 'holder' of undefined

I have tested the editor plugins in a regular React app and they work fine there. This indicates that the problem lies somewhere in the integration between EditorJS and NextJS in handling the plugins. I've tried importing the editor and plugins in the componentDidMount hook using require but encountered the same issue as with dynamic imports in NextJS. I also attempted to access the component using React ref, but it seems that NextJS has some limitations with getting components' refs. Although I tried the suggested workaround, it didn't produce the desired result. It appears that the editor instance is not available until onChange is triggered, preventing plugins from hooking into the editor due to the 'prepare' property or the entire editor being undefined until an event occurs, despite the console output indicating that the editor is ready.

Here's a snippet of my component's code:

import React from "react";
import dynamic from "next/dynamic";

const EditorNoSSR = dynamic(() => import("react-editor-js"), { ssr: false });
const Embed = dynamic(() => import("@editorjs/embed"), { ssr: false });

// Rest of the component code follows...

Is there a viable solution to resolve this issue? While I understand that SSR can be challenging when rendering components that interact with the DOM on the client side, I did include a condition to check if the window object is undefined, yet the issue persists in my scenario.

UPDATE:

I have discovered a potential solution that deviates slightly from the typical NextJS approach but seems to work effectively. This workaround involves creating an instance of EditorJS manually, similar to how it would be done in a standard EditorJS setup.

class Editor extends React.Component {
 // Implementation of Editor class continues here...

This alternative implementation has been successful in the context of NextJS.

I will continue refining the code and update it accordingly if I come across a more optimized solution.

UPDATE 2:

The proposed solution by Rising Odegua has proven to be effective.

Answer №1

To simplify your code and enhance modularity, it is recommended to create a separate component where you can import all the necessary tools. Here is an example:

import EditorJs from "react-editor-js";
import Embed from "@editorjs/embed";
import Table from "@editorjs/table";
// Import other tools here


const CustomEditor = () => {
    const EDITOR_JS_TOOLS = {
        embed: Embed,
        table: Table,
        // Include other tools here
    };

    return (
        <EditorJs tools={EDITOR_JS_TOOLS} />
    );
}

export default CustomEditor;

In your NextJS page, utilize dynamic importing as shown below:

let CustomEditor;
if (typeof window !== "undefined") {
  CustomEditor = dynamic(() => import('../src/components/CustomEditor'));
}

You can then use your custom component in the following way:

return (
  {CustomEditor && <CustomEditor />}
)

For more details, refer to the source: https://github.com/Jungwoo-An/react-editor-js/issues/31

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The keyDown function in P5.play.js does not seem to be working properly

Can someone please help me figure out why this code isn't functioning properly? I am utilizing p5 libraries such as p5.play, p5.js, p5.sound, and p5dom. Here's the snippet: class Player{ constructor(){ this.x, this.y, this.width, ...

Storing each item in its own document within a Firebase collection

I have a feature where users input their sitemap and it generates all the links in the sitemap. How can I then store each of those links in separate documents within a specific collection on Firebase? Below is the current function used to set data in Fir ...

Guide on how to conditionally render Container Classes

Initially, the designer provided me with this: Essentially, a category is passed from the previous screen. Through some UI interactions, I have to render this screen repeatedly. The flow goes like this: you choose a category, if it has subCategories, allo ...

Utilizing AJAX response to update the current URL in a Spring MVC application - A step-by-step guide

In my ongoing project using Spring MVC, the homepage features two input fields of String type. However, the regNo field accepts numbers as input. If a user enters a regNo, it should be directed to a specific method in the controller. On the other hand, if ...

Directing users to a specific section on another webpage can be accomplished using HTML, JavaScript, or

<nav> <div class='container-fluid'> <h1 class='logo'>Logo</h1> <ul class='list-unstyled naving'> <li><a href='index.html'>Home</a></li> ...

How to Populate Object Literal with Multiple Objects in AngularJS

When I click on "Evan", I receive the following response: {"id":1,"name":"Evan"} If I click on "Robert", I will get: {"id":2,"name":"Robert"} Is there a way to modify this code so that it follows the aforementioned steps and generates an object similar ...

What is the reason onbeforeunload does not fire requests in Safari browser?

Is there a way to ensure that data is saved to the database when a user interacts with the page and also when they refresh it? I have tried using onbeforeunload event, but Safari does not wait for the server request to finish before reloading the page, c ...

How can I trigger an onclick event for a link automatically upon loading in Laravel?

I am presenting the link below: <a href="javascript:void(0)" onclick="xtenderSearchItem.modal_visibility = ! xtenderSearchItem.modal_visibility;">Request</a> My goal is for it to change the language of the page (which occu ...

Efficient method for handling numerous AJAX requests

I have a web application that currently makes 14-15 AJAX calls to various APIs. The issue is that the combined time it takes for all the AJAX calls to complete is significantly longer than when I individually type each API's URL into the browser. Cur ...

TypeScript error: Unable to locate namespace 'ng'

I am attempting to utilize a tsconfig.json file in order to avoid having /// <reference tags at the beginning of multiple files. However, I keep encountering this error: [ts] Cannot find namespace 'ng'. any Here is my configuration within ...

Javascript error in formatting

Currently, I am utilizing an inner join operation on three tables and displaying the resulting table using XML. <SQLInformation> <Table>tblechecklistprogramworkpackagexref prwpxref</Table> <TableJoins> INNER JOI ...

Using an ASP.NET control along with jQuery within a standalone .js file

I recently created a jQuery voting script that functions perfectly when the code is kept within the header of the page. However, I am interested in transferring it to a separate .js file and simply including this .js file at the top of the page. Strangely, ...

Trouble Arising from Making a POST Request to Spotify's API

I am currently developing a web application that allows users to search the Spotify Library, add songs to playlists, and then save those playlists to their Spotify Accounts. Almost everything is functioning correctly except for the saving of playlists thro ...

Tips for integrating an arrow function as a property in a functional programming approach using JavaScript or TypeScript

Suppose I were to create a constructor for a functional class with TypeA as an argument, and TypeB representing the type of the class itself. In such cases, I can implement it using: functionName(argument: TypeA): TypeB { this.property = argument; ...

Ways to allow scroll events on top of an overlay without passing click events

My goal is to develop a unique map annotation tool with custom controls, not relying on the built-in features of map providers. Imagine something like this: https://i.sstatic.net/70Yj7.gif I had the idea of placing a canvas over the map for this purpose ...

A guide to implementing API calls within a MERN Stack application with Server Side Rendering

I'm currently working on a server-side rendered React app and I'm having trouble setting up API calls to fetch data from the database. In typical MERN apps with REST APIs, we receive data from the server based on requested routes through res.data ...

Choose between creating an observable pipe within a function or storing it in a variable

Currently, I have a functional code snippet that leverages the Angular service to create an Observable pipeline. This pipeline utilizes operators like mergeMap, filter, map, and shareReplay(1) to manage user authentication and fetch the onboarding status f ...

Cropped portion of the captcha image located on the left side

edit: I manually adjusted cnv.width = this.width to 120 and it seems to be working. Upon closer inspection, I discovered that the image has both a rendered size and an intrinsic size. The width is 35 for rendered size and 40 for intrinsic size, which may e ...

A message appeared in the console warning about Vue using canvas-datagrid

Everything is displaying correctly as I intended. However, there is a warning in the console: > vue.js:2 [Vue warn]: Unknown custom element: <canvas-datagrid> - did > you register the component correctly? For recursive components, make > sur ...

Tips for implementing the f11 effect with a delay of 5 seconds after pressing a key in JavaScript or jQuery

Is there a way to activate the F11 effect only 5 seconds after pressing a key using JavaScript or jQuery? ...