Search code examples
javascriptwebpackgatsbyscrollmagic

Scrollmagic with Gatsby js and window undefined upon deploy


My Gatsby site can't be deployed to Netlify because of a WebpackError: ReferenceError: window is not defined

I've tried:

  1. Wrapping return statements in if(window !== undefined) checks which didn't work
  2. Putting a require statement in my index.js: if (typeof window !== 'undefined') { require('scrollmagic') require('scrollmagic-plugin-gsap') } which didn't work

I noticed that the import statement import Scrollmagic from 'scrollmagic' already causes the error because I once tried deploying the site without any scrollmagic code except for the import.

The scrollmagic part of my component looks like this (I deleted some irrelevant variable assignments in this example):

import React, { useRef, useEffect } from 'react'
import ScrollMagic from "scrollmagic"
import { TweenMax, TimelineMax, Power3, TweenLite, TimelineLite } from "gsap"
import { ScrollMagicPluginGsap } from "scrollmagic-plugin-gsap";

const Techstack = () => {
  ScrollMagicPluginGsap(ScrollMagic, TweenMax, TimelineMax);

  const techs = useRef()
  const trigger = useRef()


  useEffect(() => {
    let controller = new ScrollMagic.Controller()
    const techitems = techs.current.children
    const tl = new TimelineMax
    for (let i = 0; i < techitems.length; i++) {
      new ScrollMagic.Scene({
        triggerElement: techitems[i],
      })
        .setTween(TweenLite.from(techitems[i], 1, { opacity: 0, x: -300, ease: Power3.easeOut }))
        .addTo(controller)
    }
  }, [])


    return (
      <TechstackContainer ref={trigger} id="trigger">
        <ContentWrapper ref={techs}>
          <StyledTechstackText>
            Ich baue Webseiten und Apps, am liebsten mit:
        </StyledTechstackText>
          {stack.map(el => {
            return <TechItem>{el}</TechItem>
          })}
        </ContentWrapper>
      </TechstackContainer>
    )
}

How would I go about it?


Solution

  • I can't see where do you call window on your code but the way to solve this all issues is to delay the window call after the component is rendered using a componentDidMount (in class-based component) or useEffect with empty deps ([]) in stateless-based component. So, you need to do something like this:

      useEffect(() => {
        if(typeof window !== undefined){
          let controller = new ScrollMagic.Controller()
          const techitems = techs.current.children
          const tl = new TimelineMax
          for (let i = 0; i < techitems.length; i++) {
            new ScrollMagic.Scene({
              triggerElement: techitems[I],
            })
              .setTween(TweenLite.from(techitems[i], 1, { opacity: 0, x: -300, ease: Power3.easeOut }))
              .addTo(controller)
          }
        }
      }, [])
    

    Note the typeof window !== undefined condition.

    However, if you are using third-party libraries that uses the window to do their stuff, you will need to put this snippet in your gatsby-node:

    exports.onCreateWebpackConfig = ({ actions, loaders, getConfig, stage }) => {
      const config = getConfig();
    
      config.module.rules = [
        // Omit the default rule where test === '\.jsx?$'
        ...config.module.rules.filter(
          rule => String(rule.test) !== String(/\.jsx?$/)
        ),
    
        // Recreate it with custom exclude filter
        {
          ...loaders.js(),
    
          test: /\.jsx?$/,
    
          // Exclude all node_modules from transpilation, except for 'swiper' and 'dom7'
          exclude: modulePath =>
            /node_modules/.test(modulePath)
        },
      ];
    
      if (stage.startsWith('develop') && config.resolve) {
        config.resolve.alias = {
          ...config.resolve.alias,
          'react-dom': '@hot-loader/react-dom'
        }
      }
    };
    

    According to Gatsby documentation:

    One solution is to customize your webpack configuration to replace the offending module with a dummy module during server rendering.

    Source: https://www.gatsbyjs.org/docs/debugging-html-builds/#fixing-third-party-modules