ReferenceError: Window is Not Defined in Gatsby

Hero image for ReferenceError: Window is Not Defined in Gatsby. Image by Laurent Perren.
Hero image for 'ReferenceError: Window is Not Defined in Gatsby.' Image by Laurent Perren.

In my current project, I oversee three associate developers; these are hyperintelligent junior developers, fresh out of code camp. I've always enjoyed working in a mentoringtype role, especially when their questions can leave you unsure of the 'why' behind some of the things we do every day in web development.

Today though, I was approached about an incredibly common earlysteps issue when attempting to build a Gatsby site:

WebpackError: ReferenceError: window is not defined
Screenshot of Terminal during a Gatsby build displaying the error message: 'WebpackError: ReferenceError: window is not defined'.

This can be particularly vexing when you've inevitably been developing and running the site locally via gatsby develop with no hint of an issue. Fortunately, the answer is very, very simple.


The Cause

It may be very obvious what the issue is, but just in case: when running a build within the Node.js environment, browser Global Variables such as window or document do not exist, so any code that references them will fail unless suitably safeguarded. There are two very straightforward ways around this:

Ensure that window and/or document is defined before calling

Adding a little safeguarding to your code will ensure that we don't end up in a situation where you're attempting to call browser variables that don't exist. This isn't going to be as simple as just testing !window, but it's also not much more complicated:

// if true, then we are rendering in-browsertypeof window !== 'undefined'

You can also take this one step further and check for the existence of document too if for example you need to access documentElement to toggle a classname, although in most cases this wouldn't be necessary:

typeof window !== 'undefined' && document

Move the code into the componentDidMount lifecycle

If your code sits within one of your React.js components, then you can simply move it within the component's lifecycle using componentDidMount or a useEffect hook. These only run when the component is mounted in a browser, so you can be safe in the knowledge that window does indeed exist at that point.

useEffect(() => {  // global browser variables will always exist here}, []);
Photograph of a stack of wooden blocks by Volodymyr Hryshchenko on Unsplash.

Issues with Third‑Party Modules

It's all very well and good knowing how to resolve these types of build errors within your own code, but what about when the issue lies within a thirdparty module which simply assumes that window always exists? Aside from opening a ticket and hoping that the developer sees the error in their ways, there are a couple of options available.

Conditionally Require a Module

Expanding on the safeguarding we discussed above, it is possible to conditionally require a module within your code:

if (typeof window !== 'undefined') {  const module = require('module');}

Or inline using a simple ternary:

const module = typeof window !== 'undefined' ? require('module') : null;

If you go down this route, you will then of course need to ensure that each use of the module within your component is wrapped in a conditional too.

Use a dummy placeholder during build

In Gatsby, you can also tie into the Gatsby Node API and simply swap the offending module out during the SSR build process.

Direct from the Gatsby docs on the subject, simply add the following code to your gatsbynode.js file. If your project doesn't have a gatsbynode.js file yet, you can simply create one in the root of your project and it will be picked up next time you run Gatsby.

exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {  if (stage === 'build-html' || stage === 'develop-html') {    actions.setWebpackConfig({      module: {        rules: [          {            test: /naughty-module/,            use: loaders.null(),          },        ],      },    });  }};

I explicitly mention Gatsby in the title and throughout this article, but it's worth mentioning that the exact same is true if you come across this error on buildtime in any serverside rendered framework, like Next.js.


Categories:

  1. Gatsby
  2. JavaScript
  3. Next.js
  4. Node.js
  5. Server‑Side Rendering