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

Server side rendering doesn't work. #870

Closed
antherkiv opened this issue Jun 6, 2017 · 18 comments
Closed

Server side rendering doesn't work. #870

antherkiv opened this issue Jun 6, 2017 · 18 comments

Comments

@antherkiv
Copy link

Hello, thanks for the great work you are doing here. I have a minor issue, due to get-window (https://github.com/webmodules/get-window) library using in several places in the core (plugins, models, etc.), slate doesn't work in the server-side, get-window using browser only variables like window and document, I understand is using to detect if the window is an iframe.

Best regards.

@tashburn
Copy link
Contributor

I also really need server-side rendering to work (with next.js)

@danburzo
Copy link
Contributor

@antherkiv can you paste an example or a stacktrace of the error you're getting, so people tackling this issue have a starting point? It's not immediately clear how this would break, since window methods tend to be used in response to user interaction.

@HaNdTriX
Copy link

If you need a quick workarond. You can import your slate editor with dynamic imports.
This allows you to render the Editor Component on client only.

import React from 'react'
import dynamic from 'next/dynamic'

const DynamicLoadedEditor = dynamic(
  import('./MyAwesomeSlateEditor'),
  {
    loading: () => (<p>loading...</p>),
    ssr: false
  }
)

export default DynamicLoadedEditor

@tashburn
Copy link
Contributor

@HaNdTriX Thanks for the idea.

@HaNdTriX
Copy link

Just to clarify. I am using slate with next.js and it works like a charm.
The markup is rendered on the server without my workaround above.
Thanks for the great work @ianstormtaylor!

@rkrueger11
Copy link

@HaNdTriX Did you have to do anything special to get it to render server side w/ Next.js? I keep getting an error: Unable to find a DOM node for "3". This is often because of forgetting to add props.attributes to a custom component.

@HaNdTriX
Copy link

HaNdTriX commented Aug 5, 2018

@rkrueger11 yes you need to reset the key generating function.
I just created a next.js example for this.

Next.js-Example

vercel/next.js#4899

SSR-Example

import React from 'react'
import Plain from 'slate-plain-serializer'
import { Editor } from 'slate-react'
import { KeyUtils } from 'slate'

class Index extends React.Component {
  constructor (props) {
    super(props)

    // In order to allow ssr we need to reset the key
    // generating function to its initial state.
    KeyUtils.resetGenerator()

    // Deserialize the initial editor value.
    this.state = {
      value: Plain.deserialize(
        'This is editable plain text, just like a <textarea>!'
      )
    }
  }

  render () {
    return (
      <Editor
        placeholder='Enter some plain text...'
        value={this.state.value}
        onChange={this.onChange}
      />
    )
  }

  onChange = ({ value }) => {
    this.setState({ value })
  }
}

export default Index

@ianstormtaylor I think this issue can be closed.

@ianstormtaylor
Copy link
Owner

Thanks @HaNdTriX!

@HaNdTriX
Copy link

HaNdTriX commented Aug 7, 2018

There is now an offical next.js example: https://github.com/zeit/next.js/tree/canary/examples/with-slate

@josephmaxim
Copy link

josephmaxim commented Aug 16, 2018

@HaNdTriX It works but when you clear the inputbox and type something on the field again it gives the error: Unable to find a DOM node for "2". This is often because of forgetting to addprops.attributes to a custom component.

EDIT: Only happens in express custom server.

EDIT 2: Fixed! for some weird reason it works when you close chrome dev tools.

@nickjackson
Copy link

I've got multiple instances of slate on a page, and @HaNdTriX's fix won't work for me.

Whenever I try and focus one of the slate instances, it will always focus the first one. https://codesandbox.io/s/zkzx818ryx. I presume this is because the keys are being reused across instances.

I'm not sure of a fix that will work with SSR and multiple instances. The global nature of KeyUtils isn't ideal.

Any ideas?

@dankythuat
Copy link

If you need a quick workarond. You can import your slate editor with dynamic imports.
This allows you to render the Editor Component on client only.

import React from 'react'
import dynamic from 'next/dynamic'

const DynamicLoadedEditor = dynamic(
  import('./MyAwesomeSlateEditor'),
  {
    loading: () => (<p>loading...</p>),
    ssr: false
  }
)

export default DynamicLoadedEditor

thank, this's really works

@nickjackson
Copy link

nickjackson commented Nov 2, 2018

@tuanhuu

thank, this's really works

Yeah I'll have to do this for now I think, but it's not really a fix.

@ianstormtaylor should I raise another issue for this?

@rklhui
Copy link

rklhui commented Nov 11, 2018

Just tried the quick fix disabling SSR for the editor component in React, it works! But still waiting for a proper fix that works with SSR @ianstormtaylor

The KeyUtils.resetGenerator() works for slate instances that rendered with SSR, but crash for slate instances that are later generated on the client side (got max callstack error once I focus on the slate editor)

Here is how I quick fix it for now:

import React from "react"
let SlateEditor

class Editor extends React.Component {
  componentDidMount() {
    SlateEditor = require("./SlateEditor").default
  }

  render() {
    if (SlateEditor) {
      return (
        <SlateEditor
          {...this.props}
        />
      )
    }
    return null
  }
}

export default Editor

@juhaelee
Copy link

juhaelee commented Jan 5, 2019

@HaNdTriX any tips on getting this to work with multiple slate instances?

@aquiseb
Copy link

aquiseb commented Jan 11, 2019

@juhaelee the issue is that data-key are starting from 0 for each instance of the Editor due to KeyUtils.resetGenerator(). So when clicking on an Editor, it focuses to the first data-key of the dom, thus being the first Editor instance and the second one becomes unfocusable.

Slate provides a KeyUtils.setGenerator(myKeygenFunction) to pass our own key generator. This gives us the opportunity to create truly unique keys across Editor instances.

In the parent that imports this component, pass a different idFromParentIteration prop for each instance of PlainText component and you should be good. Like so:

['first-editor', 'second-editor'].map((name, idx) => <PlainText idFromParentIteration={name + idx} />)

And here's a complete example with a custom key generator.

import React from "react";
import Plain from "slate-plain-serializer";
import { KeyUtils } from 'slate';
import { Editor } from "slate-react";

const initialValue = Plain.deserialize(
  "This is editable plain text, just like a <textarea>!"
);

class PlainText extends React.Component {
  constructor(props) {
    super(props);
    let key = 0;
    const keygen = () => {
      key += 1;
      return props.idFromParentIteration + key; // custom keys
    };
    KeyUtils.setGenerator(keygen);
  }
  render() {
    return (
      <Editor
        placeholder="Enter some plain text..."
        defaultValue={initialValue}
      />
    );
  }
}

export default PlainText;

@oyeanuj
Copy link
Contributor

oyeanuj commented Jan 25, 2019

@rklhui I'm facing the same issue and have to disable SSR to have the editor not crash in editing mode. Did you figure out a different solution?

@jonathaneckman
Copy link

What is the solution in Slate 0.50+ now that KeyUtils has been removed?

HaNdTriX added a commit to HaNdTriX/next.js that referenced this issue Sep 9, 2020
## Changelog

- Updated slate.js to version 0.58.4
- Removed unused packages (immutable & slate-plain-serializer)
- Simplified example (we don’t need to demonstrate the multi editor case anymore since this issue is now handled by slate internally)
- Remove deprecated `KeyUtils`
- Removed deprecated Components

## Related:

- ianstormtaylor/slate#870
kodiakhq bot pushed a commit to vercel/next.js that referenced this issue Sep 9, 2020
## Changelog

- Updated slate.js to version 0.58.4
- Removed unused packages (immutable & slate-plain-serializer)
- Simplified example (we don’t need to demonstrate the multi editor case anymore, since this issue is now handled by slate internally)
- Remove deprecated `KeyUtils`
- Removed deprecated Components

## Related:

- ianstormtaylor/slate#870
HitoriSensei pushed a commit to HitoriSensei/next.js that referenced this issue Sep 26, 2020
## Changelog

- Updated slate.js to version 0.58.4
- Removed unused packages (immutable & slate-plain-serializer)
- Simplified example (we don’t need to demonstrate the multi editor case anymore, since this issue is now handled by slate internally)
- Remove deprecated `KeyUtils`
- Removed deprecated Components

## Related:

- ianstormtaylor/slate#870
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests