gatsby: Window is not defined at production build

Description

I want to trigger window width to change the content of my website. But I don’t know how to fix my issue. Webpack error : window is not defined at production build

Expected result

Production build successful.

Actual result

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { Helmet } from 'react-helmet'
import Link from 'gatsby-link'
import 'flexboxgrid/dist/flexboxgrid.min.css';
import { Footer, Header } from '../components/organisms'
import { Modal, Project } from '../components/molecules'

import '../scss/main.scss'

class Index extends Component {

  constructor(props) {
    super(props)
   this.state = {
    width: window.innerWidth,
    };
  }
  componentDidMount() {
    const width = typeof window !== 'undefined' && window
  }

  componentWillMount() {
    window.addEventListener('resize', this.handleWindowSizeChange);
  }

  // make sure to remove the listener
  // when the component is not mounted anymore
  componentWillUnmount() {
    window.removeEventListener('resize', this.handleWindowSizeChange);
  }

  handleWindowSizeChange = () => {
    this.setState({ width: window.innerWidth });
  };
  
  render(){
    const { width } = this.state;
    const isMobile = width <= 600;
    console.log(width, ' px')
    const {data} = this.props;

    return(
      <div className="wrapper">
      
        <div className="wrapper__top">
            <Helmet>
            <html lang="fr" />
            <meta charSet="utf-8" />
            <meta httpEquiv="X-UA-Compatible" content="IE-edge,chrome=1" />
            <meta name="viewport" content="width=device-width,initial-scale=1" />
            <link rel="icon" type="image/png" href="/favicon.png" />
          </Helmet>
          <Header />
          <main>
           {/* Affichage du Teaser pour les navigateurs qui ont une largeur supérieure ou égale à 600px */}
           {
             (isMobile && this.props.location.pathname === '/') ? 
             <div>
             {data.allProjectsJson.edges.map(({ node }, i) =>
                       (<Project
                           key={i}
                           title={node.title}
                           category={node.category}
                           image={{
                               src: node.image.childImageSharp.original.src,
                               alt: node.title,
                           }}
                          logo={{
                            src: node.logo.childImageSharp.original.src,
                            alt: node.title,
                          }}
                           website={node.website}
                       >
                           <p dangerouslySetInnerHTML={{ __html: node.description }} />
                       </Project>),
                   )}
              </div> 
             : this.props.children()
           }

          </main>
          <Footer />
        </div>
       
        
        
        
      </div >
    )
  }
}
Index.propTypes = {
  children: PropTypes.func.isRequired,
  location: PropTypes.shape({
    pathname: PropTypes.string,
  }).isRequired,
  data: PropTypes.object.isRequired
};
export default Index;
export const getSiteHeader = (siteTitle, description) =>
  (<Helmet>
    <title>{`${siteTitle} | Maral Sabbagh`}</title>
    <meta name="description" content={description} />
  </Helmet>);

  
//eslint-disable-next-line no-undef
export const pageQuery = graphql `
query LayoutQuery {

 allProjectsJson {
    edges {
      node {
        title
        category
        description
        image {
          childImageSharp {
            original {
              src
            }
          }
        }
        logo {
          childImageSharp {
            original {
              src
            }
          }
        }
        website
      }
    }
  }
   allGeneralJson(filter: {url: {eq: "/projets"}}){
    edges{
      node{
        url
        pageTitle
        metaDesc
        metaTitle
        

      }
    }
  }
}
`;


Environment

 gatsby info --clipboard
module.js:549
    throw err;
    ^

Error: Cannot find module 'regenerator-runtime/runtime'
    at Function.Module._resolveFilename (module.js:547:15)
    at Function.Module._load (module.js:474:25)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (C:\Users\Maral Sabbagh\AppData\Roaming\npm\node_modules\gatsby-cli\lib\index.js:88:1)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)

Thanks for your help

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 8
  • Comments: 18 (5 by maintainers)

Most upvoted comments

Posting this here since I spent a good chunk of my Friday on this last week.

  • Periodically build your Gatsby site as you’re developing it so you’re aware of such issues as you’re developing, not the day of the launch. Don’t rely too much on the development experience. Build has its own gotchas (including this one) that you’d want to learn about early on.
  • 3rd party libraries that depend on window can be fixed as mentioned in the docs. You can include multiple window-dependent libraries in one go:
rules: [{
  test: /bad-module|another-one|and-a-third-one/,
  use: loaders.null(),
}]
  • Write a simple util function like so export const isBrowser = () => typeof window !== 'undefined' and then use it everywhere: import { isBrowser } from './utils'; {isBrowser() && <CodeThatNeedsWindow />}

I had this issue and I did this.


  const [hasRan, setHasRan] = useState(false)
  const [screenSize, setScreenSize] = useState({
    height: 0,
    width: 0,
  })
  const updateScreenSize = () => {
    setScreenSize({ width: window.innerWidth, height: window.innerHeight })
  }
  useEffect(() => {
    if (!hasRan) {
      setHasRan(true)
      updateScreenSize()
    }
    window.addEventListener("resize", updateScreenSize)
    return () => {
      window.removeEventListener("resize", updateScreenSize)
    }
  }, [screenSize])

It solved my issue 😁

constructor(props) {
    super(props)
   this.state = {
    width: window.innerWidth, // this line is the culprit
    };
  }

I strongly suggest you use react-media for this case.

But if you don’t want to, changing to this should fix it:

class Index extends Component {
  constructor(props) {
    super(props)
    this.state = {
      width: 0, // or your default width here
    }
  }
  componentDidMount() {
    this.handleWindowSizeChange() // Set width
    window.addEventListener('resize', this.handleWindowSizeChange)
  }

  componentWillMount() {
    // Don’t use this as the API is deprecated
  }

  // make sure to remove the listener
  // when the component is not mounted anymore
  componentWillUnmount() {
    window.removeEventListener('resize', this.handleWindowSizeChange)
  }

  handleWindowSizeChange = () => {
    this.setState({ width: window.innerWidth })
  }

  // rest of code
}

Also note that there will be small hit to performance, unless you debounce the resize eventListener. Let me know if you need more help!

@daxaxelrod i had a similar issue with that a while ago while trying to get a resize event to work. a good workaround that did the trick for me was:

componentDidMount() {
    if (typeof window !== 'undefined') {
      window.addEventListener('resize', this.setChartDimensions)
    }
   ------
  }
  componentWillUnmount() {
    if (typeof window !== 'undefined') {
      window.removeEventListener('resize', this.setChartDimensions)
    }
  }

I’m actually having a similar issue. I have this search page and I allow the user to press enter to fire off a redux action. When an action is dispatch, props changes forcing a rerender. When the user then goes to another page, i get window.removeEventListener is not defined. Here’s my code.

error



constructor(props){
    super(props);
    this.enterToSearch = this.enterToSearch.bind(this);
    this.state = {
      searchTerm: ""
    }
  }

  enterToSearch = (event) => {
    if (event.keyCode == 13) { //enter key
      this.props.Actions.searchZA(this.state.searchTerm);
      this.setState({searchTerm: ""})
    }
  }


  componentDidMount(props){
    window.addEventListener("keydown", this.enterToSearch)
    if (this.props.ZA == []){
      this.setState({ZA: "Nothing here"});
    } else {
      this.setState({ZA: this.props.ZA});
    }
  }


  componentWillUnmount() {
    window.removeEventListner("keydown", this.enterToSearch)
  }

This isn’t issue with Gatsby. Just one of the gotchas of server-side rendering with React.

When Node tries to build, it instantiates the class, and in the constructor finds window, which is a browser global (Node doesn’t have window).

EDIT: it doesn’t have to be zero. Just as long as you don’t mention window it should be fine.

(navigate('/app/login'))}

this navigate function of gatsby is causing issues for me. while running npm build it says: window is not available during server side rendering. and :

var navigate = function navigate(to, options) { window.___navigate(rewriteLinkPath(to, window.location.pathname), options); }; exports.navigate = navigate;

(indicates at window) Any possible solutions for me?

@antoinerousseau wow I need to start using a linter. Thanks 😊

@daxaxelrod you have a typo, that’s why. removeEventListner => removeEventListener

Anybody have a sense of how to fix this error for AudioContext()? The only way I’ve ever used it is mounting to the window object - is there another way to do this? I’m trying to use the react-media-player component. Same issue as others in this thread - works fine in dev mode working with the client but when you build out for SSR, I’m getting the window is not defined:

import React, { Component } from 'react'
import { Media, Player, controls } from 'react-media-player'
import PlayPause from './PlayPause'
import MuteUnmute from './MuteUnmute'

const { CurrentTime, SeekBar, Duration, Volume } = controls

const audioContext = new (window.AudioContext || window.webkitAudioContext)()
const panner = audioContext.createPanner()

panner.setPosition(0, 0, 1)
panner.panningModel = 'equalpower'
panner.connect(audioContext.destination)


class AudioPlayer extends Component {
  componentDidMount() {
    const source = audioContext.createMediaElementSource(this._player.instance)
    source.connect(panner)
    panner.connect(audioContext.destination)
  }

  _handlePannerChange = ({ target }) => {
    const x = +target.value
    const y = 0
    const z = 1 - Math.abs(x)
    panner.setPosition(x, y, z)
  }

  render() {
    return (
      <Media>
        <div>
          <Player
            ref={c => this._player = c}
            src={this.props.src}
            useAudioObject
          />
          <section className="media-controls">
            <div className="media-title-box">
              <PlayPause className="media-control media-control--play-pause"/>
              <div className="media-title-content">
                <div className="media-title">{ this.props.mediaTitle }</div>
                <div className="media-subtitle">{ this.props.mediaSubtitle }</div>
              </div>
            </div>
            <div className="media-controls-container">
              <CurrentTime className="media-control media-control--current-time"/>
              <SeekBar className="media-control media-control--volume-range"/>
              <Duration className="media-control media-control--duration"/>
            </div>
            <div className="media-sound-controls">
              <MuteUnmute className="media-control media-control--mute-unmute"/>
              <Volume className="media-control media-control--volume"/>
            </div>            
          </section>
        </div>
      </Media>
    )
  }
}

export default AudioPlayer