gridsome / gridsome

⚡️ The Jamstack framework for Vue.js
https://gridsome.org
MIT License
8.55k stars 489 forks source link

ScrollMagic + GSAP gives me “window is not defined” on "gridsome build" #882

Open OziOcb opened 4 years ago

OziOcb commented 4 years ago

After installing both and combining them to work together, ScrollMagic gives me a "window is not defined" error. I've already tried many solutions, but I'm still struggling with it. Can someone help me, please? Or suggest a good alternative for ScrollMagic+GSAP?

(Link to the repo on GitHub.)

I installed them via yarn. yarn add scrollmagic gsap

In main.js I added: (I followed this)

/* GSAP & ScrollMagic */
import  ScrollMagic  from  "scrollmagic"
import  "imports-loader?define=>false!scrollmagic/scrollmagic/uncompressed/plugins/animation.gsap"

// Load ScrollMagic's Indicators only on development environment
if (process.env.NODE_ENV  ===  "development") {
    require("imports-loader?define=>true!scrollmagic/scrollmagic/uncompressed/plugins/debug.addIndicators")
}

const  GSAPScrollMagic  =  {
    install(Vue,  options)  {
        // GSAP
        Vue.prototype.$GSAP  =  {
            TweenMax,
            TimelineMax,
            Linear,
            Power1,
            Power2,
            Power3,
            Back
        }

        // ScrollMagic
        Vue.prototype.$ScrollMagic  =  {
            Controller:  new  ScrollMagic.Controller(),
            Scene:  ScrollMagic.Scene
        }
    }
}

export  default  function(Vue,  {  router,  head,  isClient  })  {
    // Add GSAP & ScrollMagic to the project
    Vue.use(GSAPScrollMagic)
}

And in my pages/index.vue file i simply add it like this:

<script>
export  default  {
    ...
    mounted()  {
    // create a Tween
    const  testTween  =  new  this.$GSAP.TimelineMax()
    testTween
        .from(".smElement",  1.5,  { ease:  this.$GSAP.Power2.easeOut, opacity:  0  })

    // create a scene
    const  testScene  =  new  this.$ScrollMagic.Scene({
        triggerElement:  ".smElement",
        triggerHook:  0.7,
        duration:  300
    })
        .addIndicators()
        .setTween(testTween)

    // Add the scene to the controller
    this.$ScrollMagic.Controller.addScene(testScene)
    }
}
</script>

everything works great on 'gridsome develop'. On 'gridsome build' I get this error:

Gridsome v0.7.10

Initializing plugins...
Load sources - 0.06s
Create GraphQL schema - 0.09s
Create pages and templates - 0.05s
Generate temporary code - 0.06s
Bootstrap finish - 1.92s
10% building 1/1 modules 0 active
  Update available: 0.3.1
  Run yarn add global @gridsome/cli to update

Compile assets - 20.38s
Execute GraphQL (6 queries) - 0.02s
Write out page data (6 files) - 0s
Could not generate HTML for "/blog/test/":
ReferenceError: window is not defined
    at Object.<anonymous> (node_modules/scrollmagic/scrollmagic/uncompressed/ScrollMagic.js:37:0)
    at assets/js/app.a4f12461.js:3124:37
    at Object.<anonymous> (node_modules/scrollmagic/scrollmagic/uncompressed/ScrollMagic.js:27:1)
    at __webpack_require__ (webpack/bootstrap:25:0)
    at Module.<anonymous> (assets/js/app.a4f12461.js:12578:19)
    at __webpack_require__ (webpack/bootstrap:25:0)
    at Object.<anonymous> (assets/js/app.a4f12461.js:8588:18)
    at __webpack_require__ (webpack/bootstrap:25:0)
    at assets/js/app.a4f12461.js:118:18
    at Object.<anonymous> (assets/js/app.a4f12461.js:121:10)

# I've found a similar issue with ScrollMagic on Nuxt.js, but I'm not sure how to convert the solution to Gridsome.

I've also tried to follow the official docs for adding external script without SSR support, with no luck...

dominiquedutra commented 4 years ago

@OziOcb I am not familiar with scrollmagic, but did you wrap your component on tags on your html? This tells gridsome that this component should not be SSR.

Please check my (last) comment on this issue: https://github.com/gridsome/gridsome/issues/394 It may help you.

jpcarpenter commented 4 years ago

@OziOcb Did you ever solve this issue? I'm currently dealing with the same thing at the moment.

brandonpittman commented 4 years ago
if (!process.isClient) return
jpcarpenter commented 4 years ago

@brandonpittman where would you suggest to put that in relation to @OziOcb above code examples?

brandonpittman commented 4 years ago

@jpcarpenter Just stick it at the top of any function you don't want running at build time. I'd just put it at the top of mounted() and be done with it. Also, importing something that's auto-injecting crap into window is going to fail. Check the docs for ways around it. Usually involves require()ing in a mounted() call.

jpcarpenter commented 4 years ago

Thanks for the direction @brandonpittman. What I ended up doing was creating an alias to ScrollMagic and all it's dependencies in gridsome.server.js, then using require() to include them on any given template, whilst checking if process.isClient before outright initiating ScrollMagic itself. Full working example below:

gridsome.server.js:

var path = require('path');
api.configureWebpack({
    resolve: {
      alias: {
        "TweenLite": path.resolve('node_modules', 'gsap/src/uncompressed/TweenLite.js'),
        "TweenMax": path.resolve('node_modules', 'gsap/src/uncompressed/TweenMax.js'),
        "TimelineLite": path.resolve('node_modules', 'gsap/src/uncompressed/TimelineLite.js'),
        "TimelineMax": path.resolve('node_modules', 'gsap/src/uncompressed/TimelineMax.js'),
        "ScrollMagic": path.resolve('node_modules', 'scrollmagic/scrollmagic/uncompressed/ScrollMagic.js'),
        "animation.gsap": path.resolve('node_modules', 'scrollmagic/scrollmagic/uncompressed/plugins/animation.gsap.js'),
        "debug.addIndicators": path.resolve('node_modules', 'scrollmagic/scrollmagic/uncompressed/plugins/debug.addIndicators.js')
      }
    },
  })

Component.vue This is a full working example of ScrollMagic in use that plays nice with gridsome at build time.

 mounted() {

    // Require ScrollMagic
    if (!process.isClient) return;
    let ScrollMagic;
    ScrollMagic = require("ScrollMagic");
    require("animation.gsap");
    require("debug.addIndicators");

      ...

    // Build out GSAP animations
    const timeline = new TimelineMax();

      ...

    // Set up ScrollMagic controller and scene
    let sm = {
      Controller: new ScrollMagic.Controller(),
      Scene: ScrollMagic.Scene
    };

    // Set up ScrollMagic to trigger everything
    const scene = new sm.Scene({
      triggerElement: "#myTriggerId"
    })
      .addIndicators()
      .setTween(timeline);

    // Add the scene to the controller
    sm.Controller.addScene(scene);

  }
rhanmiano commented 4 years ago

Hi @jpcarpenter , may I know which version of GSAP you've used in your snippet? I've run into the same issue but using GSAP3. I can't seem to fix the issue with your code example.

What I used for the path is the umd one which is indicated in the install process of GSAP3.

//gridsome.server.js
const path = require('path');
api.configureWebpack({
    resolve: {
      alias: {
        "gsap-umd": path.resolve('node_modules', 'gsap/dist/gsap')
      }
    },
  })

And required it in my component like this

mounted() {
    if (!process.isClient) return
    const { TimelineLite, Back } = require("gsap-umd")
     // elements to be animated
    const { title, kicker, logo, explore, soc1, soc2, soc3, socWrap } = this.$refs

    const timeline = new TimelineLite()

    // some animation code here
}

Same issue. Works fine in the development server, but with no good after building the static files.

jpcarpenter commented 4 years ago

@rhanmiano I was using 2.1.3 on this project. I've never used the UMD versions, I used the raw source code files which are modern ES6 modules. Maybe Gridsome is doing something different with the compiling of the ES6 modules during the build process than with the UMD versions?

rhanmiano commented 4 years ago

Thanks for the response @jpcarpenter ! There is this weird encounter when trying the built files in my local server (using node's http-server). On load, the animation I did for the page does not work. But when I go to the same page through navigation, everything seems working fine.

I tried deploying my changes to a live server, and funny, all animations work just how I expected it to be.

I'm not really sure where the issue lies exactly in my local environment. But your code suggestion did work in my end, instead of just normally importing the module. Thank you.

jpcarpenter commented 4 years ago

@rhanmiano It sounds like the animation isn’t being triggered on initial mount, but on the route change. I’ve read about this issue that sounds somewhat similar to yours when using the <transition> tag to animate the entire page in/out. May or may not be related, since it ends up working fine in your production environment.