Gatsby: Window is not defined at production build

Created on 11 Jun 2018  ·  18Comments  ·  Source: gatsbyjs/gatsby

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

Most helpful comment

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 />}

All 18 comments

window isn't available when building a site — check out this page for some work arounds https://www.gatsbyjs.org/docs/debugging-html-builds/#how-to-check-if-code-classlanguage-textwindowcode-is-defined

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!

@ryanditjia thanks I'll check, I didn't know that I had to set the inner width to 0. For this project I won't use this module but for the next It could be more simpler.
Thank you so much

It could be great if this issue could be be fixed in the next version of Gatsby @KyleAMathews

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.

@ryanditjia thanks for the explanation :)
Everything works fine now :)

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)
  }

@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)
    }
  }

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

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

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

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 😁

Hello,

Got the same issue.
'gatsby build' throws me this

failed Building static HTML for pages - 9.517s

 ERROR #95312 

"window" is not available during server side rendering.

See our docs page for more info on this error: https://gatsby.dev/debug-html


  216 | 
  217 |   // Find the supported transform prop and style names.
> 218 |   var docElemStyle = window.document.documentElement.style;
      | ^
  219 |   var style = 'transform';
  220 |   var styleCap = 'Transform';
  221 |   var found = false;


  WebpackError: ReferenceError: window is not defined

  - muuri.js:218 
    node_modules/muuri/dist/muuri.js:218:1

  - muuri.js:19 
    node_modules/muuri/dist/muuri.js:19:63

  - muuri.js:22 Object../node_modules/muuri/dist/muuri.js
    node_modules/muuri/dist/muuri.js:22:2

  - index.js:1 Object../node_modules/muuri-react/build/index.js
    node_modules/muuri-react/build/index.js:1:1034

  - index.js:1 n
    node_modules/muuri-react/build/index.js:1:112

  - index.js:1 Module.<anonymous>
    node_modules/muuri-react/build/index.js:1:15762

  - index.js:1 n
    node_modules/muuri-react/build/index.js:1:112

  - index.js:1 ./node_modules/muuri-react/build/index.js
    node_modules/muuri-react/build/index.js:1:915


Any idea how to tackle this problem ?
Thanks !

@pmarxbraun it seems it's related to the muuri-react package, as that package is trying to write access the window api that is not acessible during the build process with Gatsby. You have options here, you can try and see if this helps with your case or try "offloading" the component where that package is used with loadable-components like mentioned here. Otherwise feel free to provide a minimal reproduction following these steps with that package and the code you're using so that it can be better looked at.

@jonniebigodes Thanks for your advice. I finnaly used "@loadable/component" to fix the problem.

My scenario: try to use "swagger-ui-react" in Gatsby, but receive ReferenceError: window is not defined.

Firstly, I tried adding some code to gatsby-browser.js, but it didn't work as below:
import SwaggerUI from 'swagger-ui-react';
window.SwaggerUI = SwaggerUI;

Next, I tried your advice "load-component", and it worked for my case.
import Loadable from '@loadable/component';
const SwaggerUI = Loadable(() => import('swagger-ui-react'));
export default () => ( <SwaggerUI /> )

@beckzayi no need to thank, just glad that you managed to solve your issue aswell.

using globalThis works just fine. It wont work in old browsers though i.e nothing but i.e. :)
Can some one help me understand if it has any caveats?

(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 atwindow)
Any possible solutions for me?

Was this page helpful?
0 / 5 - 0 ratings