react-spaces icon indicating copy to clipboard operation
react-spaces copied to clipboard

SSR on 0.2.0: ReferenceError: document is not defined

Open karl-run opened this issue 3 years ago • 5 comments

Describe the bug

react-spaces tries to access the document global on the server side execution. Stack trace:

ReferenceError: document is not defined
    at updateStyleDefinition (<snip>/node_modules/react-spaces/dist/index.js:1:6669)
    at Object.addSpace (<snip>/node_modules/react-spaces/dist/index.js:1:12033)
    at useSpace (<snip>/node_modules/react-spaces/dist/index.js:1:17621)
    at SpaceInner (<snip>/node_modules/react-spaces/dist/index.js:1:20542)
    at processChild (<snip>/node_modules/react-dom/cjs/react-dom-server.node.development.js:3353:14)
    at resolve (<snip>/node_modules/react-dom/cjs/react-dom-server.node.development.js:3270:5)
    at ReactDOMServerRenderer.render (<snip>/node_modules/react-dom/cjs/react-dom-server.node.development.js:3753:22)
    at ReactDOMServerRenderer.read (<snip>/node_modules/react-dom/cjs/react-dom-server.node.development.js:3690:29)
    at renderToString (<snip>/node_modules/react-dom/cjs/react-dom-server.node.development.js:4298:27)
    at renderPage (<snip>/node_modules/next/dist/next-server/server/render.js:53:851)
    at Object.ctx.renderPage (webpack-internal:///./src/pages/_document.tsx:79:26)
    at Function.getInitialProps (webpack-internal:///../../node_modules/next/dist/pages/_document.js:135:19)
    at Function.MyDocument.getInitialProps (webpack-internal:///./src/pages/_document.tsx:87:83)
    at loadGetInitialProps (<snip>/node_modules/next/dist/next-server/lib/utils.js:5:101)
    at renderToHTML (<snip>/node_modules/next/dist/next-server/server/render.js:53:1142)
    at async <snip>/node_modules/next/dist/next-server/server/next-server.js:98:97

To Reproduce Steps to reproduce the behavior:

  1. Use react-spaces in a server environment, e.g. nextjs

Expected behavior Should render as normal

Package versions (please complete the following information):

  • React version: 17.0.1
  • React spaces version: ^0.2.0

Desktop (please complete the following information):

  • OS: Manjaro
  • Browser Chrome
  • Version 87

I see previously there was a separate dist folder for an SRR-enabled version of react-spaces, however I can't find any traces of it in the newest version. :) If you want I can set up a quick nextjs repro repo.

karl-run avatar Jan 05 '21 14:01 karl-run

Hi @karl-run Thanks for reporting. If you could setup a repro repo that would be great!

aeagle avatar Jan 08 '21 18:01 aeagle

Sure thing!

https://github.com/karl-run/react-spaces-repro

karl-run avatar Jan 09 '21 13:01 karl-run

@karl-run I ran into this too, I think it's a problem w/ Next.js's SSR, the fix here worked for me.

cktang88 avatar May 12 '21 20:05 cktang88

@cktang88 It's correct that you can "fix" this issue by limiting the execution of react-spaces to the client. But a library such as react-spaces in typically something that you would want to execute on the server side because it's part of the layout.

The earlier you "exit" the rendering on your server, the more of the initial rendering has to be done on the client. In my app react-spaces was pretty high up in the rendering tree, so if I were to use the fix you linked I would just have a single page application, but with more steps. :)

karl-run avatar May 13 '21 09:05 karl-run

Hi all. I've played around with the repro and whilst it's easy to stop the reference to document server side, because currently the library relies quite heavily on the first render to create the correct layout between spaces the result is not good once the styling/initial mark-up actually hits the client.

I'm looking into a solution to ensure the correct info makes it's way from server-side -> client-side to render the layout correctly and will keep you posted.

For now unfortunately the only workaround is to configure the react-spaces as client execution only.

aeagle avatar May 14 '21 12:05 aeagle

I am still looking into this to see what's feasible.

I've released a small fix (v0.3.9) to avoid document is not defined errors when components are being rendered in a server-side environment. However bear in mind that this is not a full SSR implementation.

Pro:

  • Spaces and their content should now be able to be rendered server-side without error

Con:

  • Space styling and positioning is not rendered server-side. Styling will still be rendered client-side once the component is hydrated however there is a caveat that all spaces must be explicitly given a unique id prop for this to currently work correctly rather than relying on a dynamically given id as default.

aeagle avatar Jan 06 '23 17:01 aeagle

Ok. I've added full support (experimental) in v0.4.0. It's opt in at the moment by added the <SSR /> component from the library before any use of spaces.

There are some caveats:

  • You must be using React 18 as the functionality depends on new functionality in that version, namely the useId() hook for consistent ID generation between server and client renders. This does mean that you now do not explicitly need to set an id on spaces as mentioned before.
  • Ordering of spaces in the JSX/TSX matters in a SSR scenario. Because a <Fill /> is dependent on renders of all anchored spaces around it to determine it's size, you should always place the <Fill /> space last within a parent. This is so that it's correct size is determined in the first render. I would imagine that if you are using stacked anchored spaces, then they should appear in the JSX/TSX in the order they are stacked also.

I know this has been a long time coming but would be good to know if this works for you in your use cases.

aeagle avatar Jan 06 '23 23:01 aeagle

Going to close this as resolved. Feel free to reopen if you are still having issues.

aeagle avatar Jan 19 '23 20:01 aeagle