Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"ReferenceError: document is not defined" in Next.js13 & 14 #1119

Open
eliyo opened this issue Nov 1, 2023 · 14 comments
Open

"ReferenceError: document is not defined" in Next.js13 & 14 #1119

eliyo opened this issue Nov 1, 2023 · 14 comments

Comments

@eliyo
Copy link

eliyo commented Nov 1, 2023

I am using plyr-react in a Next.js 14.0.1 environment (also tried with v13) and pages using plyr-react (5.3.0) fail to load or build with errors of type "ReferenceError: document is not defined" node_modules\plyr\dist\plyr.js:302:21

From my understanding, it seems the runtime tries to access the document object where there isn't one, like when running in a server environment. These errors can be fixed by checking validity of the document object before accessing it, but I don't think this is a proper fix, it seems the code is being run within a context it shouldn't be run into.

Windows 10, Node.js 21.1.0, Next.js 14.0.1, plyr-react 5.3.0, react 18.2.0

FYI I didn't have this problem when I worked on my site about 6 months ago, but now I upgraded everything I have it all the time, this blocks the build.

Steps to reproduce:

  1. install latest next.js and example app using: npx create-next-app@latest
  2. npm install plyr-react
  3. into the app's src/app/page.tsx, import plyr and and a tag in the Home function.
import Plyr from "plyr-react"
import "plyr-react/plyr.css"
(...)
<Plyr (...) />
  1. npm run dev
  2. open page in browser and see the error "ReferenceError: document is not defined"
@maxiedaniels
Copy link

Same issue here. No idea what changed, please let me know if there's a package update that broke Plyr...

@chintan9
Copy link
Owner

@maxiedaniels @eliyo @Clueed
I have created discussing on nextjs repo

vercel/next.js#58911

please add more question and details also there

@timomedia
Copy link

@maxiedaniels @eliyo @Clueed I have created discussing on nextjs repo

vercel/next.js#58911

please add more question and details also there

I don't know if this is an error due to nextjs version or your source code. But this error appears in nextjs 14.0.2 and above, but 14.0.1 still works normally.

@maxiedaniels
Copy link

The error disappeared for me, no idea why. I had already tried deleting node_modules and my package lock file, but it hadn’t fixed it. I gave up and then somehow a day later I realized the error had disappeared.

@the-rich-piana
Copy link

Also getting this error but with Remix

@DarKS4ys
Copy link

DarKS4ys commented Jan 7, 2024

same, got this error with nextjs 14.0.2

@timomedia
Copy link

timomedia commented Jan 19, 2024

same, got this error with nextjs 14.0.2
@chintan9
It only has errors with version 14.0.2 and above. Even the latest version 14.1.0 still has this error, however next.js seems to ignore it and allow buid.

@maxiedaniels
Copy link

@timomedia it allows me to run npm run dev if I recall but I can’t do an actual build or deploy on vercel

@sekmet
Copy link

sekmet commented Feb 5, 2024

Hello,
To fix it, make it client a component and use next dynamic import

const Plyr = dynamic(() => import("plyr-react"), { ssr: false });

it should work ;)

@c0bra
Copy link

c0bra commented Feb 6, 2024

Hello, To fix it, make it client a component and use next dynamic import

const Plyr = dynamic(() => import("plyr-react"), { ssr: false });

it should work ;)

This works to render, but it doesn't seem possible to get the ref to to the component. If you just attach the ref prop you get Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()

All my attempts beyond this to dynamically import usePlyr and do React.forwardRef() have failed, as well as all attempts to do a basic forwarded-ref component.

Currently stuck with not being able to use this library, which is a bummer.

@michaelpumo
Copy link

michaelpumo commented Feb 20, 2024

I was getting this problem too but I now resolved it (I think). Here's an example component if it helps anyone out there:

"use client";

import { FC } from "react";
import dynamic from "next/dynamic";
import "plyr-react/plyr.css";

const Plyr = dynamic(async () => await import("plyr-react"), { ssr: false });

type Video = {
  id: string;
  source: Plyr.Provider;
};

type Props = {
  video?: Video;
};

const VideoPlayer: FC<Props> = ({ video, ...rest }) => {
  return video?.id && video?.source ? (
    <Plyr
      {...rest}
      source={{
        type: "video",
        sources: [{ src: video.id, provider: video.source }],
      }}
      options={{
        controls: [
          "play",
          "play-large",
          "progress",
          "current-time",
          "mute",
          "volume",
          "fullscreen",
        ],
      }}
    />
  ) : null;
};

export default VideoPlayer;

Interestingly, if I add className onto the <Plyr /> component, it completely breaks it. Very odd. e.g. <Plyr className="this-will-break" />. Perhaps usage of the hook might be better for these cases?

@maxiedaniels
Copy link

maxiedaniels commented Feb 21, 2024

The dynamic load fixed it for me (const Plyr = dynamic(() => import("plyr-react"), { ssr: false });)
edit I was getting a VERY weird bug that was breaking fast refresh and also an entire component, turns out it was this fix. So i had to do:

const PlyrComponent = React.useMemo(() => {
return dynamic(() => import("plyr-react"), { ssr: false });
}, []);

And then <PlyrComponent ...> instead of <Plyr ...>

Just sharing in case someone else has the same bug!

@timomedia
Copy link

timomedia commented Mar 23, 2024

@maxiedaniels @michaelpumo
It really doesn't work. I tried using dynamic but it didn't work. I created a component called Player to use in different pages and using it the way you do doesn't work at all. Below is my original code that tried to use dynamic

"use client"
import React, { useEffect, useRef } from "react";
import dynamic from "next/dynamic";
import Hls from "hls.js";

const PlyrComponent = dynamic(() => import("plyr-react"), { ssr: false });
export default function Player({ videoUrl, poster }) {
    const option = {
        autoplay: false,
        controls: [
            'rewind',
            'play',
            'fast-forward',
            'progress',
            'current-time',
            'duration',
            'mute',
            'volume',
            'settings',
            'quality',
            'fullscreen',
        ],
    };
    const ref = useRef(null);

    useEffect(() => {
        const loadVideo = async () => {
            if (ref.current && typeof window !== 'undefined') {
                const plyr = ref.current.get('plyr');
                if (plyr) {
                    var hls = new Hls();
                    hls.loadSource(videoUrl);
                    hls.attachMedia(plyr.media);

                    hls.on(Hls.Events.MANIFEST_PARSED, function () {
                        plyr.play();
                    });
                }
            }
        };
        loadVideo();
    }, [videoUrl]);
    return (
        <PlyrComponent
            ref={ref}
            playsInline
            source={{
                type: "video",
                sources: [{ src: videoUrl, type: 'application/vnd.apple.mpegurl' }],
            }}
            poster={poster}
            options={option}
        />
    );
}

@chintan9
Copy link
Owner

A workaround could be to create a wrapper component around the Plyr component that uses a callback ref to provide access to the underlying Plyr instance. Here's an example:

import React, { useRef, useEffect } from 'react';
import dynamic from 'next/dynamic';

const Plyr = dynamic(() => import('plyr-react'), { ssr: false });

const PlyrWrapper = ({ options, source, ...props }, ref) => {
  const plyrRef = useRef();

  useEffect(() => {
    if (plyrRef.current) {
      ref.current = plyrRef.current.plyr;
    }
  }, [plyrRef, ref]);

  return <Plyr ref={plyrRef} options={options} source={source} {...props} />;
};

export default React.forwardRef(PlyrWrapper); 

In this code, PlyrWrapper is a component that wraps the Plyr component. It uses a callback ref (plyrRef) to get a reference to the Plyr component, and then assigns the Plyr instance (plyrRef.current.plyr) to the forwarded ref (ref).

You can then use this PlyrWrapper component like this:

import PlyrWrapper from './PlyrWrapper';

function MyComponent() {
  const plyrRef = useRef();

  // You can now access the Plyr instance via plyrRef.current

  return <PlyrWrapper ref={plyrRef} /* your props here */ />;
}

This should allow you to get a ref to the Plyr instance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants