Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for SSR #58

Open
kyryloren opened this issue Jul 17, 2020 · 22 comments
Open

Support for SSR #58

kyryloren opened this issue Jul 17, 2020 · 22 comments
Assignees
Labels
enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed

Comments

@kyryloren
Copy link

kyryloren commented Jul 17, 2020

Hello.

This module doesn't support server side rendering.
When building on Netlify or on local production, I get an error that says "'window' is not available during server side rendering", and a bunch of code that is returned from the EditorJS plugin(s).

This is how I currently fixed this:

const MyComponent = () => {
  if (typeof window !== 'undefined') {
    const Editor = require('./editor').default;

    return <Editor />;
  }

  return null;
};

Even though this works, it's very 'hacky'. Please fix this.

I'm using GatsbyJS version 2.23.12.

@Jungwoo-An Jungwoo-An added enhancement New feature or request good first issue Good for newcomers labels Jul 20, 2020
@Jungwoo-An Jungwoo-An self-assigned this Jul 20, 2020
@kyryloren
Copy link
Author

Update: While this is being patched you can add the following to your gatsby-node.js file (if you're using Gatsby). If you aren't using Gatsby, you can use https://github.com/gregberge/loadable-components

exports.onCreateWebpackConfig = ({ stage, actions, loaders }) => {
  if (stage === 'build-html') {
    actions.setWebpackConfig({
      module: {
        rules: [
          {
            test: /react-editor-js/,
            use: loaders.null(),
          },
          {
            test: /@editorjs/,
            use: loaders.null(),
          },
        ],
      },
    });
  }
};

You can read more about this code here: https://www.gatsbyjs.org/docs/debugging-html-builds/#fixing-third-party-modules

@Moikapy
Copy link

Moikapy commented Jul 23, 2020

I've been using NextJS and SSR with Editor JS and this works for me

import React, { useEffect, useRef, useState } from 'react';
import EditorJs from 'react-editor-js';
import List from '@editorjs/list';
import Paragraph from '@editorjs/paragraph';
const EDITOR_JS_TOOLS = {
  paragraph: {
    class: Paragraph,
    inlineToolbar: true,
  },
  list: {
    class: List,
    inlineToolbar: true,
  },
};
export default ({
  id,
  label,
  labelStyle,
  editorContainerStyle,
  getValue,
  Data,
}) => {
  const instanceRef = useRef(null);
  async function handleSave() {
    // const savedData = await
    instanceRef.current
      .save()
      .then((outputData) => {
        function replaceAll(str, find, replace) {
          function escapeRegExp(string) {
            return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
          }
          return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
        }
        let stringData = JSON.stringify(outputData);
        let formattedData = replaceAll(stringData,'<b>','<strong>');
        formattedData = replaceAll(stringData, '<b/>', '<strong/>');
        getValue(formattedData);
      })
      .catch((error) => {
        console.log('Saving failed: ', error);
      });
  }
  console.log(Data)
  return (
    <div>
      <style global jsx>
        {`
          .ce-block__content {
            max-width: 100%;
            margin: 0 5rem;
          }
          .ce-toolbar__content {
            max-width: 100%;
            margin: 0 3.5rem;
            position: relative;
          }
          .editor-style {
            border-radius: 0.25rem;
            border-color: #ced4da;
          }
        `}
      </style>
      <label
        htmlFor={id}
        className={
          typeof labelStyle === 'undefined' || labelStyle === null
            ? `label-style`
            : `label-style {labelStyle}`
        }>
        {label}
      </label>
      <div
        className={`border rounded ${
          typeof editorContainerStyle !== undefined
            ? editorContainerStyle
            : null
        }`}>
        <EditorJs
          holder={id}
          instanceRef={(instance) => (instanceRef.current = instance)}
          data={
            typeof Data === 'string' && Data.length !== 0
              ? console.log(JSON.parse(Data))
              : Data
          }
          onChange={(e) => handleSave(e)}
          tools={EDITOR_JS_TOOLS}>
          <div id={id} />
        </EditorJs>
      </div>
    </div>
  );
};

@nithinkashyapn
Copy link

Hey @Moikapy,

Can you please share the code? I copied your above snippet in an index.js file for NextJS but got the below error -

Server Error

ReferenceError: window is not defined
This error happened while generating the page. Any console logs will be displayed in the terminal window.

Thanks

@Jungwoo-An
Copy link
Owner

Hi! everyone.

By default, editor-js does not support SSR. But i think if modern fornt-end library, should help users not to care.

Therefore, this issue not close differently from other related issues (#31, #1), and will be updated asap.

Thanks!

@thinnakrit
Copy link

I use import loadable from '@loadable/component'

example :

import loadable from '@loadable/component'
const EditorJs = loadable(() => import('~/utils/editors'))

@gufranmirza
Copy link

This is an open issue with @editorjs codex-team/editor.js#1036

@solidassassin
Copy link

NextJS has a function to ensure that React components work properly with dynamic imports. Something like this should work in theory:

import dynamic from "next/dynamic";

const EditorJs = dynamic(() => import("react-editor-js"));
// Use EditorJs as component

@HaNdTriX
Copy link

This should work:

const EditorJs = dynamic(() => import("react-editor-js"), {
  ssr: false,
  loading: () => <p>loading editor.js ...</p>,
});

@Moikapy
Copy link

Moikapy commented Feb 15, 2021

NextJS has a function to ensure that React components work properly with dynamic imports. Something like this should work in theory:

import dynamic from "next/dynamic";

const EditorJs = dynamic(() => import("react-editor-js"));
// Use EditorJs as component

This will work @nithinkashyapn

@pacochim
Copy link

pacochim commented Mar 4, 2021

Hi guys, question, editor is ok now, but, when i try to load a plugin, app crashes, asking for "window" again

@MohdAhmad1
Copy link

Make editor in another component and import it in your main page as a dynamic component

this is working fine while ssr and without any type error because importing react-editor-js as a dynamic component it loses its type definitions

eg: my Editor component ( RTE.tsx )

import EditorJs from "react-editor-js";
import { EDITOR_JS_TOOLS } from "./constants";

export default function RTE_Component() {
  return (
    <EditorJs
      tools={EDITOR_JS_TOOLS}
      data={[
        time: 1556098174501,
        blocks: [{ type: "header", data: { text: "Guides", level: 2 } }],
        version: "2.12.4",
      ]}
      inlineToolbar={true}
      hideToolbar={true}
    />
  );
}

my index.tsx

import dynamic from "next/dynamic";
import Head from "next/head";

const RTE_Component = dynamic(() => import("components/RTE"), { ssr: false });

export default function Home() {
  return (
    <>
      <Head>Localhost - Home</Head>

      <form action="http://localhost:3000/api/post" method="post">
        <RTE_Component />
      </form>
    </>
  );
}

@artm
Copy link

artm commented Apr 11, 2021

@bilordigor the solution by @zakiAzfar helps with the plugins as well: plugins have to be imported and configured in the component imported dynamically with ssr disabled.

@Jungwoo-An Jungwoo-An added the help wanted Extra attention is needed label Apr 24, 2021
@thealpha93
Copy link

Using the require statement in the useEffect hook solved this issue for me in Nextjs. Thanks

import {useEffect} from 'react'


export default function editor() {
    useEffect(() => {
        const Editorjs = require('@editorjs/editorjs')
        new Editorjs('editorjs')
    }, [])


    return(
        <div id='editorjs'></div>
    )
}

@Darren120
Copy link

Make the editorJS a child component, then you just need to import dynamically in your pages.

@ngmiduc
Copy link

ngmiduc commented Dec 22, 2021

I am also running into issues in running nextJs with this editorComponent.
I am running :

import dynamic from "next/dynamic";

const EditorJs = dynamic(() => import("react-editor-js"));
// Use EditorJs as component

and it should work, but it doesn't which is weird ...

RE:EDIT:

Actually it works now. I have downgraded to version 1.9.0. I was running in version 2. So maybe there is something wrong with version 2. Error is something like

Check your code at Editor.js:11. at Editor at LoadableImpl

@adriangzz
Copy link

This worked for me using the newest version.

Editor.tsx

import { useCallback, useRef } from "react";
import { createReactEditorJS } from "react-editor-js";

const Editor = () => {
  const ReactEditorJS = createReactEditorJS();

  const editorJS = useRef(null);

  const handleInitialize = useCallback((instance) => {
    editorJS.current = instance;
  }, []);

  const handleSave = useCallback(async () => {
    const savedData = await editorJS.current.save();
  }, []);

  return <ReactEditorJS onInitialize={handleInitialize} />;
};

export default Editor;

index.tsx

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

const EditorJs = dynamic(() => import("./Editor"), {
  ssr: false,
});

const index = () => {
  return <EditorJs />;
};

export default index;

@dmitryshelomanov
Copy link

If I need initial data on ssr ?

@Jungwoo-An
Copy link
Owner

react-editor-js is support SSR partially.

const ReactEditorJS = createReactEditorJS();

<ReactEditorJS holder="ssrHolder" /> // works fine!

@sdarnadeem
Copy link

const tools = dynamic(() => import("./tools"), { ssr: false });

@Chiranjeev-droid
Copy link

Chiranjeev-droid commented Dec 18, 2022

How to do dynamic import in nextjs 13 beta version?
What would be the equivalent code in beta next 13 js?
// let CustomEditor = dynamic(() => import("../../components/tools"), {
// ssr: false,
// });
.....

codex-team/editor.js#2223 (comment)

const tools = dynamic(() => import("./tools"), { ssr: false });

@shaikharfan7
Copy link

Anyone tried rendering multiple holders with dynamic divs/holder ids? - If I disable SSR I get TypeError:EditorJS is not a constructor.

@Eugene-Mokrushin
Copy link

Eugene-Mokrushin commented Jan 6, 2024

@Chiranjeev-droid
Wackiest solution, couldn't think of anything else though.

If anyone else knows better approach for Next 13-14, please share and tag me

"use client";
import { createReactEditorJS } from "react-editor-js";
import { EDITOR_JS_TOOLS } from "./tools";
import { useEffect } from "react";
import ReactDOM from "react-dom";
const ReactEditorJS = createReactEditorJS();
function Editor({ blocks }: any) {
  useEffect(() => {
    const holder = document.getElementById("holder");
    if (!holder) return;
    const Editor = (
      <ReactEditorJS
        tools={EDITOR_JS_TOOLS}
        defaultValue={blocks}
        placeholder={`Write from here...`}
        minHeight={900}
        inlineToolbar={true}
      />
    );
    const portalElement = ReactDOM.createPortal(Editor, holder);
    // @ts-ignore
    ReactDOM.createRoot(holder).render(portalElement);
  }, [blocks]);
  return <></>;
}

export default Editor;

P.S. Don't forget to set position of holder to relative

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests