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.


Stephen Gream

Written by Stephen Gream who lives and works in Melbourne, Australia. You should follow him on Minds