mmm
mmm

Reputation: 1436

ScrollMagic loses functionality after Gatsby build

Problem: I tried to implement ScrollMagic via NPM to Gatsby. While during development (gatsby develop) ScrollMagic works, after gatsby build and gatsby serve ScrollMagic either shows an error or loses its functionality (both steps described below).

What I want to achieve? Working ScrollMagic after Gatsby build.

I would be thankful for all your tips!


1. step I did: when you try build Gatsby project with ScrollMagic inside, it will show you an error:

  36 |  // TODO: temporary workaround for chrome's scroll jitter bug
> 37 |  window.addEventListener("mousewheel", function () {});
     | ^
  38 | 
  39 |  // global const
  40 |  var PIN_SPACER_ATTRIBUTE = "data-scrollmagic-pin-spacer";


  WebpackError: ReferenceError: window is not defined

Obviously, this happens because Gatsby uses Node environment to create a build with static files and window object is not accessible in Node.

The build is therefore not finished and not successfully created. Gatsby documentation has an advise for this specific "window not defined problem" (step 2).


2. step I did: I copied the code from Gatsby website and pasted to my gatsby-node.js:

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

By doing this and writing gatsby build and gatsby serve, Gatsby successfully built the web. But after I go to the subpage, where ScrollMagic should be included, it just does not work and ScrollMagic loses its functionality.


my GSAP and ScrollMagic packages:

"scrollmagic": "^2.0.5",
"gsap": "^3.2.4"

My Gatsby file where ScrollMagic should do its magic:

import React from "react"
import { graphql, Link } from "gatsby"
import SEO from "../components/SEO"
import Layout from '../layouts/Layout'
import SubpageHeader from '../components/SubpageHeader'
import SubpageItem from '../components/SubpageItem'
import styled from "styled-components"
import { gsap } from "gsap";
import ScrollMagic from 'scrollmagic';

export const query = graphql`
{
    prismic {
        allAbouts {
            edges {
                node {
                short_footer_text
                }
            }
        }
        allProjectssubpages {
            edges {
                node {
                    intro_text_to_projects
                    ordered_projects {
                        link_to_project {
                            ... on PRISMIC_Project {
                                _meta{
                                    uid
                                }
                                project_title
                                project_description
                                photos {
                                    photo
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
`

const MainContainer = styled.div`
    margin: 6rem 15vw 0;
    display: flex;
`

const ItemsContrainer = styled.div`
    width: 45vw;
`

const LinksContainer = styled.div`
    width: 25vw;
`

const LinksInnerContainer = styled.div`
    display: flex;
    flex-direction: column;
`
const LinkTag = styled(Link)`
    text-decoration: none;
    font-size: 16px;
    color: #000;
    margin-bottom: 15px;
    letter-spacing: 2px;
    opacity: 0.5;
`

class projects extends React.Component {
    constructor(props) {
        super(props);
    }

    componentDidMount = () => {
        const projectssubpageData = this.props.data.prismic.allProjectssubpages.edges.slice(0, 1).pop()
        const orderedProjects = projectssubpageData.node.ordered_projects;

        if (typeof window !== 'undefined') {
            let controller = new ScrollMagic.Controller();
            const itemsContainerHeight = document.querySelector('#items-container').clientHeight;
            const linksContainerHeight = document.querySelector('#links-inner-container').clientHeight;
            const height = itemsContainerHeight - linksContainerHeight;

            let scene = new ScrollMagic.Scene({ triggerElement: "#main-container", triggerHook: 0.25, duration: height })
                .setPin("#links-container")
                .addTo(controller);

            orderedProjects.forEach(project => {
                let uidOfProject = project.link_to_project._meta.uid;
                let projectDivHeight = document.querySelector(`.${uidOfProject}`).clientHeight;

                let scene = new ScrollMagic.Scene({ triggerElement: `.${uidOfProject}`, triggerHook: 0.4, duration: projectDivHeight })
                    .setClassToggle(`#${uidOfProject}`, "active")
                    .addTo(controller);
            });
        }
    }

    render() {
        const footerData = this.props.data.prismic.allAbouts.edges.slice(0, 1).pop()
        const projectssubpageData = this.props.data.prismic.allProjectssubpages.edges.slice(0, 1).pop()
        if (!projectssubpageData || !footerData) return null

        return (
            <>
                <SEO title="Projects" />
                <Layout
                    footerShortText={footerData.node.short_footer_text[0].text}
                    footerLinksArray={[
                        {
                            name: 'All Events',
                            URL: '/events'
                        },
                        {
                            name: 'Diary',
                            URL: '/diary'
                        },
                        {
                            name: 'Home',
                            URL: '/'
                        }
                    ]}>
                    {/* Subpage header */}
                    <SubpageHeader headline={"PROJECTS"} introText={projectssubpageData.node.intro_text_to_projects[0].text}></SubpageHeader>

                    <MainContainer id="main-container">
                        {/* Links to the projects */}
                        <LinksContainer id="links-container">
                            <LinksInnerContainer id="links-inner-container">
                                {projectssubpageData.node.ordered_projects.map(project => (
                                    <LinkTag
                                        to={"projects/" + project.link_to_project._meta.uid}
                                        key={project.link_to_project._meta.uid}
                                        id={project.link_to_project._meta.uid}>
                                        {project.link_to_project.project_title[0].text}
                                    </LinkTag>
                                ))}
                            </LinksInnerContainer>
                        </LinksContainer>

                        {/* All projects */}
                        <ItemsContrainer id="items-container">
                            {projectssubpageData.node.ordered_projects.map(project => (
                                <SubpageItem
                                    itemURL={"projects/" + project.link_to_project._meta.uid}
                                    photoURL={project.link_to_project.photos[0].photo.url}
                                    photoAlt={project.link_to_project.photos[0].photo.alt}
                                    title={project.link_to_project.project_title[0].text}
                                    description={project.link_to_project.project_description[0].text}
                                    divClass={project.link_to_project._meta.uid}
                                    key={project.link_to_project._meta.uid}>
                                </SubpageItem>
                            ))}
                        </ItemsContrainer>
                    </MainContainer>
                </Layout>
            </>
        )
    }
}

export default projects

Upvotes: 0

Views: 335

Answers (1)

mmm
mmm

Reputation: 1436

I did one workaround which seems to work so I am posting it here. Instead of implementing scrollmagic at the beginning of the document, I implement it later after componentDidMount is called and after I can be 100% sure that the window object exists.

here you go:

componentDidMount = () => {
        if (typeof window !== 'undefined') {
            import('scrollmagic').then((ScrollMagic) => {
                 // your scrollmagic code here
                 let controller = new ScrollMagic.Controller();
                 // ....
            });
        }
    }

This way the error disappears and therefore step 2 (step 2 from question) is not needed.

Upvotes: 2

Related Questions