Reputation: 1436
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
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