Search code examples
javascriptreactjsgatsbybulma

WebpackError: document is not defined


I'm having trouble figuring out what I'm doing wrong here/how to fix it. I'm building a site using gatsby.js and bulma. It's my first time using either and I'm getting an issue when I try and build it that reads:

WebpackError: document is not defined

The only place I'm using document is with the navbar-burger toggle code provided in the bulma docs. Everything works fine in development but breaks when building for production. This is my code:

import React from 'react'
import Link from 'gatsby-link'
import Logo from '../img/logo.png'

const Navbar = ({ siteTitle }) => (
  <div>
    <nav className="navbar is-primary is-fixed-top">
        <div className="container is-fluid">
            <div className="navbar-brand">
                <a className="navbar-item" href="../">
                    <img src={Logo} alt="Logo"/>
                </a>
                <a role="button" className="navbar-burger has-text-white" data-target="navMenu" aria-label="menu" aria-expanded="false">
                    <span aria-hidden="true"></span>
                    <span aria-hidden="true"></span>
                    <span aria-hidden="true"></span>
                </a>
            </div>
            <div className="navbar-menu" id="navMenu">
                <div className="navbar-start has-text-white">
                      <a className="navbar-item">
                        Overview
                      </a>
                      <a className="navbar-item">
                        Overview
                      </a>
                      <a className="navbar-item">
                        Overview
                      </a>
                      <a className="navbar-item">
                        Overview
                      </a>

                </div>
                <div className="navbar-end has-text-white">
                    
                      <a className="has-text-white navbar-item">
                        Overview
                      </a>
                      <div className="navbar-item">
                      <a className="button is-success is-fullwidth">
                        Request Demo
                      </a>
                      </div>
                </div>
            </div>
        </div>
    </nav>

  </div>
    
);
    
document.addEventListener('DOMContentLoaded', () => {

        // Get all "navbar-burger" elements
        const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);

        // Check if there are any navbar burgers
        if ($navbarBurgers.length > 0) {

            // Add a click event on each of them
            $navbarBurgers.forEach(el => {
                el.addEventListener('click', () => {

                    // Get the target from the "data-target" attribute
                    const target = el.dataset.target;
                    const $target = document.getElementById(target);

                    // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
                    el.classList.toggle('is-active');
                    $target.classList.toggle('is-active');

                });
            });
        }

    });

export default Navbar

Any thoughts on how to fix this are greatly appreciated. Thanks


Solution

  • This is a client-side/server-side issue.

    document is inherently client-side, since it represents the client's document. However, Gatsby renders your site server-side (when you run gatsby build).

    document will be undefined on build, and trigger an error (see the docs page Debugging HTML builds):

    Some of your code references “browser globals” like window or document. If this is your problem you should see an error above like “window is not defined”.

    Gatsby suggests two solutions:

    To fix this, find the offending code and either

    1. check before calling the code if window is defined so the code doesn’t run while Gatsby is building (see code sample below) or
    2. if the code is in the render function of a React.js component, move that code into componentDidMount which ensures the code doesn’t run unless it’s in the browser.