Esteban Gorupicz
Esteban Gorupicz

Reputation: 33

Using Glide JS with Next.js: document is not defined

I've created a plain HTML webiste with a carousel using Glide JS. Then I moved to Next JS and I'm stucked with a "ReferenceError: document is not defined" related to the script I use to run the carousel. I am aware about Node not having DOM, but still I don't know what to do to fix this.

The error here:

Server Error
ReferenceError: document is not defined

This error happened while generating the page. Any console logs will be displayed in the terminal window.
Source
components/Glide.js (3:14) @ document

  1 | import Glide from '@glidejs/glide'
  2 | 
> 3 | let sliders = document.querySelectorAll('.glide');
    |          ^
  4 | for (let i = 0; i < sliders.length; i++) {
  5 |     let glide = new Glide(sliders[i], {
  6 |         startAt: 0,

This is my code:

components/Glide.js

import Glide from '@glidejs/glide'

let sliders = document.querySelectorAll('.glide');
    for (let i = 0; i < sliders.length; i++) {
        let glide = new Glide(sliders[i], {
            startAt: 0,
            autoplay: 2800,
            hoverpause: true,
        });
        glide.mount();
    }

pages/index.js (relevant part)

import Glide from "./components/Glide"

export default function Home() {
    return(
        <>
<div className="glide-container">
    <div className="glide">
        <div data-glide-el="controls" >
            <button data-glide-dir="<" className="glide__arrow glide__arrow--left">`{'<'}`</button>
            <button data-glide-dir=">" className="glide__arrow glide__arrow--right">`{'>'}`</button>
        </div>
        <div className="glide__track" data-glide-el="track">
            <ul className="glide__slides">

                <li className="glide__slide"><img src="1.jpg" />1</li>
                <li className="glide__slide"><img src="2.png" />2</li>
                <li className="glide__slide"><img src="3.png" />3</li>
                <li className="glide__slide"><img src="4.png" />4</li>
            </ul>
        </div>

        <div className="glide__bullets" data-glide-el="controls[nav]">
            
            <button className="glide__bullet" data-glide-dir="=0"></button>
            <button className="glide__bullet" data-glide-dir="=1"></button>
            <button className="glide__bullet" data-glide-dir="=2"></button>
            <button className="glide__bullet" data-glide-dir="=3"></button>

        </div>
    </div>
</div>

 
        </>
  )
}

To reproduce the error:

  1. Create a new nextJS project by running npx create-next-app@latest and using this configuration:
  1. Install GlideJS by running npm install @glidejs/glide
  2. Create the two files described above.
  3. run npm run dev

I tried looking at here: How to use Glide js in Next js

And here: Next.js: document is not defined

But still, I can't figure out what I should do.

Upvotes: 0

Views: 463

Answers (2)

Esteban Gorupicz
Esteban Gorupicz

Reputation: 33

This is what I did and worked:

  1. Deleted Glide.js component (see question description)
  2. Replaced the original glide-container div and everything inside at pages/index.js (relevant part) (see question description) with a <GlideContainer /> tag
  3. Created GlideContainer.js component as you can see below:
import React, { useLayoutEffect } from "react";
import Glide from '@glidejs/glide';

export default function GlideContainer() {
    useLayoutEffect(() => {
       let sliders = document.querySelectorAll('.glide');
    for (let i = 0; i < sliders.length; i++) {
        let glide = new Glide(sliders[i], {
            startAt: 0,
            autoplay: 2800,
            hoverpause: true,
        });
        glide.mount();
    }

    })

    return(
        <>
            <div className="glide-container">
                <div className="glide">
                    <div data-glide-el="controls" >
                        <button data-glide-dir="<" className="glide__arrow glide__arrow--left">{'<'}</button>
                        <button data-glide-dir=">" className="glide__arrow glide__arrow--right">{'>'}</button>
                    </div>
                    <div className="glide__track" data-glide-el="track">
                        <ul className="glide__slides">

                            <li className="glide__slide"><img src="img/PastEvents/9.jpg" /></li>
                            <li className="glide__slide"><img src="img/PastEvents/10.jpg" /></li>
                            <li className="glide__slide"><img src="img/PastEvents/11.jpg" /></li>
                            <li className="glide__slide"><img src="img/PastEvents/12.jpg" /></li>
                            <li className="glide__slide"><img src="img/PastEvents/13.jpg" /></li>
                            <li className="glide__slide"><img src="img/PastEvents/14.jpg" /></li>
                            <li className="glide__slide"><img src="img/PastEvents/15.jpg" /></li>
                            
                        </ul>
                    </div>

                    <div className="glide__bullets" data-glide-el="controls[nav]">
                        
                        <button className="glide__bullet" data-glide-dir="=0"></button>
                        <button className="glide__bullet" data-glide-dir="=1"></button>
                        <button className="glide__bullet" data-glide-dir="=2"></button>
                        <button className="glide__bullet" data-glide-dir="=3"></button>
                        <button className="glide__bullet" data-glide-dir="=4"></button>
                        <button className="glide__bullet" data-glide-dir="=5"></button>
                        <button className="glide__bullet" data-glide-dir="=6"></button>
                        <button className="glide__bullet" data-glide-dir="=7"></button>
                    </div>
                </div>
            </div>
        </>)}

Upvotes: 0

Hoopra
Hoopra

Reputation: 853

NextJS works by hydrating prerendered HTML. NextJS generates HTML and js code on the server and then hands those to the browser. You are executing document.querySelector during the prerender (server), before the document is available (browser).

The trick is to use document only when it is guaranteed to be defined, like in a useLayoutEffect hook (which is only called after the component is loaded into the DOM):

pages/index.js

import Glide from "./components/Glide"

export default function Home() {
    useLayoutEffect(() => {
       // glide code here
    })

    return(
        <>
<div className="glide-container">

One way could be to write a hook called useGlide which executes useLayoutEffect.

Upvotes: 0

Related Questions