abhaynikam / react-trix-rte

React wrapper for Trix rich text editor created by Basecamp
https://abhaynikam.github.io/react-trix-rte
MIT License
71 stars 10 forks source link

Using window causes server side rendering to fail #20

Open akoskovacs opened 3 years ago

akoskovacs commented 3 years ago

Hi!

I tried to use react-trix-rte in SSR context. Of couse this means no window or document object exist, but the editor tries to access that.

This is the error I am getting:

ReactOnRails::PrerenderError in Posts#index

ERROR in SERVER PRERENDERING
Encountered error: "ReferenceError: window is not defined"
when prerendering Posts with props: {"initialPosts":{"data":[{"id":"a3b49222-9d4d-482f-92fd-d5953b066330","type":"post","attributes":{"id":"a3b49222-9d4d-482f-92fd-d5953b066330","aliasName":null,"content":"","voteCount":1,"qliqTitle":"valami","qliqUri":"hello","qliqUserUri":null,"slug":"hello","title":"hello","username":"eee","createdAt":"2020-11-29T22:02:58.611Z","updatedAt":"2020-11-29T22:02:59.567Z","linkId":null,"mediaId":null,"pollingId":null,"postItemId":"a3b49222-9d4d-482f-92fd-d5953b066330","qliqId":"47d7391a-3ee7-49cf-9dc
... TRUNCATED ...
":"7ada051c-ec5a-4bec-b6f0-fbf26c86b005","aliasName":null,"content":null,"voteCount":1,"qliqTitle":"Heiiihooo","qliqUri":"heihoo","qliqUserUri":null,"slug":"valami","title":"valami","username":"eee","createdAt":"2020-09-20T21:24:33.472Z","updatedAt":"2020-09-20T21:24:33.472Z","linkId":null,"mediaId":null,"pollingId":null,"postItemId":"7ada051c-ec5a-4bec-b6f0-fbf26c86b005","qliqId":"ef0373c7-d6ee-47e3-8c43-69e4caec991d","userAliasId":"b6cdbf5e-fa37-49fa-b074-0b90b3033e95","fullUri":"/heihoo"}}]}}

code:

        (function() {
          var railsContext = {"railsEnv":"development","inMailer":false,"i18nLocale":"en","i18nDefaultLocale":"en","rorVersion":"12.0.0","rorPro":false,"href":"http://localhost:3000/","location":"/","scheme":"http","host":"localhost","port":3000,"pathname":"/","search":null,"httpAcceptLanguage":"hu,en-US;q=0.9,en;q=0.8,ru;q=0.7,fr;q=0.6","serverSide":true};
              ReactOnRails.clearHydratedStores();

          var props = {"initialPosts":{"data":[{"id":"a3b49222-9d4d
... TRUNCATED ...
,"mediaId":null,"pollingId":null,"postItemId":"7ada051c-ec5a-4bec-b6f0-fbf26c86b005","qliqId":"ef0373c7-d6ee-47e3-8c43-69e4caec991d","userAliasId":"b6cdbf5e-fa37-49fa-b074-0b90b3033e95","fullUri":"/heihoo"}}]}};
          return ReactOnRails.serverRenderReactComponent({
            name: 'Posts',
            domNodeId: 'Posts-react-component-653bc907-72f5-43f5-84a2-b73ca4f2f561',
            props: props,
            trace: true,
            railsContext: railsContext
          });
        })()

n ((execjs):36004:7)
a ((execjs):36006:37)
t.exports ((execjs):36152:139)
Object.(execjs) (<anonymous>:35957:9)
r ((execjs):35858:19)
Module.(execjs) (<anonymous>:36242:5)
r ((execjs):35858:19)
(execjs):35894:18
(execjs):35895:4
(execjs):35843:128

Related gems used:

gem 'jquery-rails'
gem 'webpacker', '~> 5'
gem 'mini_racer', platforms: :ruby
gem "react_on_rails", "= 12.0.0

Code used:

import * as React from 'react';
import { ReactTrixRTEInput, ReactTrixRTEToolbar } from "react-trix-rte";
import { PostItem } from "./PostItem";

export interface PostEditorProps {
  post: PostItem;
}

export const PostEditor = ({ post }: PostEditorProps) => {
  function handleChange(event, newValue) {
    //... todo ...
  }

  return (
    <>
      <ReactTrixRTEToolbar toolbarId="react-trix-rte-editor" />
      <ReactTrixRTEInput
        toolbarId="react-trix-rte-editor"
        defaultValue="<div>Please, be nice!</div>"
        value={ post.content }
        isRailsDirectUpload={ true }
        onChange={handleChange}
      />
    </>);
};
abhaynikam commented 3 years ago

Thank you for the bug report 😊. I will investigate this issue and try to get back to you as soon as I can.

rash3ye commented 3 years ago

@akoskovacs

This is how I handle it

// @ts-ignore
let ReactTrixRTEInput;
let ReactTrixRTEToolbar;

function RichTextEditorComponent() {
  const [isServer, setIsServer] = useState(true);

  useEffect(() => {  
    try {
      if (window) {
        ReactTrixRTEInput = require('react-trix-rte').ReactTrixRTEInput;
        ReactTrixRTEToolbar = require('react-trix-rte').ReactTrixRTEToolbar;
        setIsServer(false);
      }
    } catch (err) {
      //
    }
  }, []);

  return (
    <div>
      {isServer ? null : (
        <>
          <ReactTrixRTEToolbar toolbarId="react-trix-rte-editor" />
          <ReactTrixRTEInput
            toolbarId="react-trix-rte-editor"
            defaultValue="<div>This works!</div>"
            onChange={console.log}
          />
        </>
      )}
    </div>
  );
}

export default RichTextEditorComponent;
abhaynikam commented 3 years ago

@akoskovacs Are you still facing this issue? Could you help me reproduce it with a sample codesandbox?

khrome83 commented 3 years ago

I tried the code from @rash3ye above in a Next.js project, and still see this issue.

It is clearly the server side rendering that is causing the issue, because it checks for window.

mech commented 2 years ago

Using Next.js also. When refreshing will hit theReferenceError: window is not defined error.

mech commented 2 years ago

For Next.js, I am using dynamic import with ssr: false to overcome this problem:

const TrixEditor = dynamic(() => import("form-controls/TrixEditor"), {
  ssr: false,
  loading: () => <p>Loading editor...</p>,
});

const NoteExample = () => {
  return (
    <TrixEditor />
  )
}