rich-markdown-editor icon indicating copy to clipboard operation
rich-markdown-editor copied to clipboard

Content is not rendered when using SSR

Open petrovalex opened this issue 5 years ago • 11 comments

Hello, trying to use this library with Nextjs, but the content is not getting rendered server side

Expected behavior Content should be rendered

Version 11.0.1

petrovalex avatar Oct 07 '20 07:10 petrovalex

Prosemirror does not support node, so to achieve this we'd have to write a renderer that emulates the output of Prosemirror – Remirror has done a good job of this, so it could be an inspiration for the work:

https://github.com/remirror/remirror/tree/master/@remirror/react-ssr

https://github.com/remirror/remirror/blob/997eb56a49ad653544fcd00b83e394e63df3a116/packages/%40remirror/react/src/renderers/react-serializer.tsx#L146

tommoor avatar Oct 07 '20 22:10 tommoor

Alright, thanks!

petrovalex avatar Oct 08 '20 08:10 petrovalex

Hi @tommoor, I get your point about Remirror, but I would expect it to work using dynamic imports with Next.js:

const Editor = dynamic(() => import('rich-markdown-editor'), {ssr: false})

const MySSRComponent = () => {

return (
  <>
    {
        !process.browser
        ? null
        : (
              <Editor
              id={/*  my id */}
              defaultValue='Default value'
              placeholder='Placeholder'
              onChange={console.log}
             />
           ) 
    }
  </>
  )
}

but it's not working anyway... any idea on that?

micheleriva avatar Oct 22 '20 11:10 micheleriva

I would expect it to work using dynamic imports with Next.js

Me too, Next must be rendering that on the server side?

tommoor avatar Oct 23 '20 03:10 tommoor

I would expect it to work using dynamic imports with Next.js

Me too, Next must be rendering that on the server side?

I've specified {ssr: false} to the dynamic import options and checked if process.browser was truthy on the client side before rendering, but it's not showing up

micheleriva avatar Oct 23 '20 06:10 micheleriva

You can create a component outside the "Page" folder and then import it dynamically inside.

import dynamic from "next/dynamic";

const Example = dynamic(() => import("../Components/<componentName>.js"), { ssr: false });

export default Example;

"Example" in this case is from the example/src/index.js file

tarsenidze avatar Dec 18 '20 23:12 tarsenidze

@tarsenidze

You can create a component outside the "Page" folder and then import it dynamically inside.

Does not work.


After lots of trial and error, I think I found a workaround that seems to work quite reliably.

import React, { memo, useEffect, useState } from "react";
import RichMarkdownEditor from "rich-markdown-editor";
import { Router } from "next/router";

const MarkdownDisplay = ({ value }: { value: string }) => {
  const [render, setRender] = useState(false);

  useEffect(() => {
    const handle = () => {
      // it doesn't work without setTimeout but I don't know why
      setTimeout(() => setRender(true));
    };

    // bind to window load event for ssr and route change event for csr
    window.addEventListener("load", handle);
    Router.events.on("routeChangeComplete", handle);

    return () => {
      window.removeEventListener("load", handle);
      Router.events.off("routeChangeComplete", handle);
    };
  }, []);

  // render the editor initially with an empty string until the document is completely loaded
  // this is important because the change in value causes prosemirror to rerender the dom correctly on the client later
  return <RichMarkdownEditor value={render ? value : ""} onChange={() => {}} readOnly />;
};

export default memo(MarkdownDisplay);

This workaround should make the editor render correctly, but only on the client. It won't be visible immediately when the page is refreshed, so there will be some waiting time for the document to load until you see something. I really find it quite unfortunate that we can't take advantage of server side rendering with this editor.

luaneko avatar Jan 31 '21 10:01 luaneko

Any update on this ?

nikita2423 avatar Apr 15 '21 14:04 nikita2423

I'm not planning on working on this at the moment, my applications do not use SSR. However if someone else wants to enable this functionality a PR would be happily accepted

tommoor avatar Apr 15 '21 15:04 tommoor

I didn't show (loading ? <Spinner/> : <Editor/>) the Markdown editor before routeChangeComplete event, this worked instead (even with navigating between two [slug].tsx dynamic pages containing this component):

const Editor: FC<{ value: string }> = ({ value }) => {
  const [render, setRender] = useState(false);
  useEffect(() => {
    setRender(true);
  }, []);

  return (
    <RichMarkdownEditor value={render ? value : undefined} />
  );
};

MonstraG avatar Apr 17 '21 17:04 MonstraG

I wanted my content to get rendered as a static page (ie, rendered at build-time), so I used the react-markdown library to display the content on the server-side (since it supports SSR), then I swapped it with rich-markdown-editor on client render. This is hacky, and the initial styles that react-markdown uses are not great so there's a flicker when rich-markdown-editor is loading, but at least the content is being rendered statically.

seeARMS avatar Jul 29 '21 03:07 seeARMS