FullCalendar with Gatsby

Filed under react on January 27, 2021

Ran into a situation a little while ago where I needed a calendar page for something I was working on, eventually settled on FullCalendar with its React docs.

I wrote up my page and got it working with the development server, only to have the following issue when I went to build my production bundle

"window" is not available during server side rendering.

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


  1 | import * as react from 'react';
  2 | import * as reactDom from 'react-dom';
> 3 | (typeof globalThis !== 'undefined' ? globalThis : window).FullCalendarVDom = {
    | ^
  4 |     Component: react.Component,
  5 |     createElement: react.createElement,
  6 |     render: reactDom.render,


  WebpackError: ReferenceError: window is not defined

Not being a JS developer normally, this led me down a bit of a rabbit hole and it took me a couple of hours to find a solution, which is

  1. Make sure Gatsby doesn’t try to compile the FullCalendar library in a static fashion
  2. Make the calendar object loadable at run time

To do this, I opened up gatsby-node.js and added this to the bottom of the file

exports.onCreateWebpackConfig = ({stage, loaders, actions}) => {
  if (stage === "build-html") {
    actions.setWebpackConfig({
      module: {
        rules: [
          {
            test: /@fullcalendar\/react/,
            use: loaders.null(),
          },
          {
            test: /@fullcalendar\/daygrid/,
            use: loaders.null(),
          },
        ],
      },
    })
  }
}

Next, I installed the react-loadable library and wrapped the calendar on the page

$ npm install --save react-loadable
const LoadableCalendar = Loadable({
    loader: () => import('@fullcalendar/react'),
    loading: () => <div>Loading...</div>,
    render(loaded, props) {
        let Cal = loaded.default;
        return <Cal {...props} />
    }
})

This let me keep the same properties as the FullCalendar component normally exposes

<LoadableCalendar
    plugins={[ dayGridPlugin ]}
    initialView="dayGridMonth"
    events={fullCalendarEvents}
/>

Build seems happy now. Hopefully this helps someone in less time than it took me.