Skip to content

Rule proposal: ssr-friendly #2057

@alexreardon

Description

@alexreardon

In order to be SSR compliant, you can only access browser globals such as window, document and so on, inside of componentDidMount, componentDidUpdate and componentWillUnmount

screen shot 2018-11-26 at 11 05 04 am

A rule could be created to avoid the use of unguarded browser globals in other lifecycle methods.

Example of a guard:

if (typeof window !== 'undefined') {
 // I can use browser globals in here
}

Use of browser globals are allowed when:

  • used in a guard
  • used in componentDidMount, componentDidUpdate and componentWillUnmount
  • used in useEffect or useLayoutEffect
  • used in an event handler

Activity

ljharb

ljharb commented on Nov 26, 2018

@ljharb
Member

This sounds like an excellent rule, and I'm very much in favor of it. A PR is appreciated!

(Note, however, that it's also acceptable to access these things in event handlers - any component method or function that is only referenced by passing it in as a prop to an element, and never directly invoked)

alexreardon

alexreardon commented on Nov 26, 2018

@alexreardon
Author

@ljharb I updated the description

alexreardon

alexreardon commented on Dec 2, 2018

@alexreardon
Author

I have not had experience writing eslint plugins before. I see the first step as fairly straight forward: checking if browser globals are called inside of componentDidMount, componentDidUpdate or componentWillUnmount.

I am not sure how to check if this is done inside of a guard such as

if (typeof window !== 'undefined') {
 // I can use browser globals in here
}

@ljharb you have any thoughts on how I could check to see if the usage of the code is guarded?

ljharb

ljharb commented on Dec 3, 2018

@ljharb
Member

Even if guarded, if initial render behavior differs between client and server, that’s a bug - so there shouldn’t be any use outside of those methods, even guarded.

alexreardon

alexreardon commented on Dec 3, 2018

@alexreardon
Author

Sometimes there might be - such as when a component mounts into a portal.

alexreardon

alexreardon commented on Dec 3, 2018

@alexreardon
Author

So on the server it might just return null, whereas in the browser it might return ReactDOM.createPortal(children, el). I have seen this pattern around

alexreardon

alexreardon commented on Dec 3, 2018

@alexreardon
Author

But I could buy that these are edge cases and a consumer could add a //eslint-ignore-next-line react/ssr-friendly

ljharb

ljharb commented on Dec 3, 2018

@ljharb
Member

That would cause a render mismatch, i believe - if you want to conditionally render into a portal, you’d need to do that using state set in componentDidMount.

alexreardon

alexreardon commented on Dec 3, 2018

@alexreardon
Author

Sounds good to me

sidharthachatterjee

sidharthachatterjee commented on Apr 10, 2019

@sidharthachatterjee

Watching this closely as this would be super useful for Gatsby

alexreardon

alexreardon commented on Apr 12, 2019

@alexreardon
Author

I hope to take more of a look at this soon!

13 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @ljharb@JasperH8g@kopiro@correttojs@osdiab

      Issue actions

        Rule proposal: ssr-friendly · Issue #2057 · jsx-eslint/eslint-plugin-react