Skip to content

npm run build : 'document is not defined' #159

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
MadeInMoon opened this issue Mar 5, 2016 · 6 comments
Closed

npm run build : 'document is not defined' #159

MadeInMoon opened this issue Mar 5, 2016 · 6 comments

Comments

@MadeInMoon
Copy link

I tried to had few UI modules (Halogen, react-spark-scroll).

When your localhost is served by the command "npm run dev", you can import your module, integrate them into your page, save your file, and that everything works fine in the browser, until you run a 'npm run build'

'document is not defined'

I think it's because of the server rendenring wich doesn't offer the window.document object.

So, in my component calling an Halogen loader for example, i have to require it like this:

let Loader;

var canUseDOM = !!(
    typeof window !== 'undefined' &&
    window.document &&
    window.document.createElement
);

if (canUseDOM) {
  Loader = require('halogen/RingLoader');
} 
else{
  Loader = class {
    render() {
      let { children, ...other } = this.props
      return <div {...other}>{children}</div>
    }
  }
}

Is it an issue depending on each module leading to this error?, or can we make something on this repo to avoid this kind of dirty fixes?

@choonkending
Copy link
Member

@MadeInMoon Good question.

I've recently been trying to create an node module for a react menu as well, and had encounter similar errors.

I think it's because of the server rendering which doesn't offer the window.document object.

That's right. I think it's because the libraries normally assume the window object is available (not a wrong assumption if you do not consider server-side rendering).

Might have to think about this. I feeeel like there s a webpack-y way to solve this. Like ignoring the module on server side compilation.

@psimyn Might be able to provide some insight because he's the webpack wiz!!

@psimyn
Copy link
Collaborator

psimyn commented Mar 5, 2016

@MadeInMoon does the wrapper you had above cause a "code rendered differently on client and server" warning in the console?

@choonkending still unsure of even a 'good' way to deal with this automatically for anything, moving the window !== undefined check into webpack define plugin is about the only change in that regard.

I had considered some kind of global try/catch thing (or try automatically wrapping stuff that references window) but I don't think it would end well. It's usually up to the component to handle server/client rendering. If there is any window references before componentDidMount it is going to render differently on server side. e.g. what would window.innerWidth return on the server?

I'll update if i think of anything better

@MadeInMoon
Copy link
Author

@psimyn yes :

capture d ecran 2016-03-05 a 17 38 20

So it's squeezing all the ismorphic benefits for all the app?

@psimyn
Copy link
Collaborator

psimyn commented Mar 5, 2016

not all - you still get a fast initial render. It just means it nukes/repaints it after that because it (correctly) detects changes.

If you don't want to fix the component, you can make it just render client side with something like:

componentDidMount() {
  setState({onClient: true});
}

render() {
  if (this.state.onClient) {
    <Loader />
  } else {
    <somePlaceholder />
}

Which may do what you want, while still being the same code client/server side

@psimyn
Copy link
Collaborator

psimyn commented Mar 5, 2016

Worth keeping an eye on webpack-contrib/style-loader#109 to see if this can be solved in webpack land

@choonkending
Copy link
Member

@psimyn 👍

You could optionally try making a High order component for this to be removed if it gets fixed in webpack land?

import {Component} from 'react';
export const onClient = ComposedComponent => class extends Component {
    componentDidMount() {
       this.setState({onClient: true});
   }

   render() {
      <ComposedComponent onClient={this.state.onClient} />
   }
}

And use this HOC like this.

import {Component} from 'react';
import {onClient} from 'onClient';

class MainContainer extends Component {
   render() {
      if (this.props.onClient) {
          return <Loader />
       }
      return <Placeholder />;
   }
}

export default onClient(MainContainer);

That way you get to still get the onClient as a prop :)

The above code hasn't been tested, but it should point you in the right direction.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants