dash.js icon indicating copy to clipboard operation
dash.js copied to clipboard

SSR error `window is not defined`

Open wintercounter opened this issue 1 year ago • 4 comments

Environment

Next.js

  • Dash.js version: 5.0.0
Steps to reproduce
  1. Add import * as DASH from 'dashjs' in a Next.js project.
Observed behavior

Throws error.

Console output
⨯ ReferenceError: window is not defined
    at (ssr)/./node_modules/dashjs/dist/modern/esm/dash.all.min.js (.next/server/vendor-chunks/dashjs.js:20:1)
    at __webpack_require__ (.next/server/webpack-runtime.js:33:43)
Expected behavior

Not failing.

wintercounter avatar Mar 23 '25 20:03 wintercounter

I don't quite understand the use case here, can you please provide more details. Do you want to use dash.js on the server side?

For playback, dash.js requires the Media Source Extensions and the Encrypted Media Extensions. If the window object is not defined, then the APIs are not available and dash.js can not be used.

dsilhavy avatar Mar 25 '25 13:03 dsilhavy

As you may know, during SSR client-side components are also run on the server. In my case in my Player component. Typicaly these cases are solved by having an if (typeof window !== "undefined") check in libraries.

wintercounter avatar Mar 25 '25 15:03 wintercounter

Hi @wintercounter,

AFAIK, even for the client components (with "use client" directive), Next.js tries to load the modules on the server side. I have tried dynamic/lazy import as suggested here: https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading. no luck. Then, I fixed the issue as follows;

export const DashPlayer: React.FC<Props> = (props: Props) => {
    const { src } = props;

    const videoRef = useRef<HTMLVideoElement>(null);
    const [dashLibrary, setDashLibrary] = useState<any>(null);

    useEffect(() => {
        const loadModule = async () => {
            try {
                setDashLibrary(await import('dashjs'));
            } catch (error) {
                console.error('Failed to load dashjs:', error);
            }
        };
        loadModule()
            .then(() => console.debug('dashjs library loaded'))
            .catch(() => console.error('Failed to load dashjs library'));
    }, []);

    useEffect(() => {
        if (!videoRef.current || !dashLibrary) return;

        const player = dashLibrary.MediaPlayer().create();
        player.initialize(videoRef.current, src, true);

        return () => {
            if (player) player.reset();
            console.debug('dashjs player destroyed');
        };
    }, [dashLibrary, src]);

    return <video ref={videoRef} />
}

please note that this is the simplified version and might be missing some points on the copy paste, but overall this is the idea.

I hope this helps.

burak-kara avatar Apr 01 '25 12:04 burak-kara

Yes, with dynamic it works. But I don't want that, I want to bundle Dash using normal import for faster initial playback.

On Tue, 1 Apr 2025, 14:53 Burak Kara, @.***> wrote:

Hi @wintercounter https://github.com/wintercounter,

AFAIK, even for the client components (with "use client" directive), Next.js tries to load the modules on the server side. I have tried dynamic/lazy import as suggested here: https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading. no luck. Then, I fixed the issue as follows;

export const DashPlayer: React.FC<Props> = (props: Props) => { const { src } = props;

const videoRef = useRef<HTMLVideoElement>(null);
const [dashLibrary, setDashLibrary] = useState<any>(null);

useEffect(() => {
    const loadModule = async () => {
        try {
            setDashLibrary(await import('dashjs'));
        } catch (error) {
            console.error('Failed to load dashjs:', error);
        }
    };
    loadModule()
        .then(() => console.debug('dashjs library loaded'))
        .catch(() => console.error('Failed to load dashjs library'));
}, []);

useEffect(() => {
    if (!videoRef.current || !dashLibrary) return;

    const player = dashLibrary.MediaPlayer().create();
    player.initialize(videoRef.current, src, true);

    return () => {
        if (player) player.reset();
        console.debug('dashjs player destroyed');
    };
}, [dashLibrary, src]);

return <video ref={videoRef} />

}

please note that this is the simplified version and I might be missing some points on the copy paste, but overall this is the idea. I hope this helps.

— Reply to this email directly, view it on GitHub https://github.com/Dash-Industry-Forum/dash.js/issues/4728#issuecomment-2769263541, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAHLJQAJSNLF446CKTUDCJD2XKD6FAVCNFSM6AAAAABZTNZJA2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDONRZGI3DGNJUGE . You are receiving this because you were mentioned.Message ID: @.***> [image: burak-kara]burak-kara left a comment (Dash-Industry-Forum/dash.js#4728) https://github.com/Dash-Industry-Forum/dash.js/issues/4728#issuecomment-2769263541

Hi @wintercounter https://github.com/wintercounter,

AFAIK, even for the client components (with "use client" directive), Next.js tries to load the modules on the server side. I have tried dynamic/lazy import as suggested here: https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading. no luck. Then, I fixed the issue as follows;

export const DashPlayer: React.FC<Props> = (props: Props) => { const { src } = props;

const videoRef = useRef<HTMLVideoElement>(null);
const [dashLibrary, setDashLibrary] = useState<any>(null);

useEffect(() => {
    const loadModule = async () => {
        try {
            setDashLibrary(await import('dashjs'));
        } catch (error) {
            console.error('Failed to load dashjs:', error);
        }
    };
    loadModule()
        .then(() => console.debug('dashjs library loaded'))
        .catch(() => console.error('Failed to load dashjs library'));
}, []);

useEffect(() => {
    if (!videoRef.current || !dashLibrary) return;

    const player = dashLibrary.MediaPlayer().create();
    player.initialize(videoRef.current, src, true);

    return () => {
        if (player) player.reset();
        console.debug('dashjs player destroyed');
    };
}, [dashLibrary, src]);

return <video ref={videoRef} />

}

please note that this is the simplified version and I might be missing some points on the copy paste, but overall this is the idea. I hope this helps.

— Reply to this email directly, view it on GitHub https://github.com/Dash-Industry-Forum/dash.js/issues/4728#issuecomment-2769263541, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAHLJQAJSNLF446CKTUDCJD2XKD6FAVCNFSM6AAAAABZTNZJA2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDONRZGI3DGNJUGE . You are receiving this because you were mentioned.Message ID: @.***>

wintercounter avatar Apr 01 '25 13:04 wintercounter