Skip to main content

SSR / Next.js

warning

Never call new EvePlayer() at module scope. It touches document and window internally, which do not exist during server-side rendering.

Use a dynamic import inside an effect, so construction runs only in the browser:

// components/VideoWrapper.tsx
'use client';
import { useEffect, useRef } from 'react';

export default function VideoWrapper() {
const containerRef = useRef<HTMLDivElement>(null);

useEffect(() => {
let player: import('@admmedia/eveplayer').EvePlayer;

void (async () => {
const { EvePlayer } = await import('@admmedia/eveplayer');
player = new EvePlayer(containerRef.current!, { widescreen: true });
player.setSource({ sources: [{ src: '/video.mp4', type: 'video/mp4' }] });
})();

return () => player?.dispose();
}, []);

return <div ref={containerRef} />;
}

Or defer the whole component with Next.js dynamic:

const VideoWrapper = dynamic(() => import('./VideoWrapper'), { ssr: false });

Until the player script runs, the container is an empty div, 0px tall. To reserve the space and avoid a layout shift, give the placeholder (and the container) the vjsp-widescreen class and create the player with widescreen: true, so both are the same 16:9 box:

const VideoWrapper = dynamic(() => import('./VideoWrapper'), {
ssr: false,
loading: () => <div className="vjsp-widescreen" />,
});

See Player sizing for the other sizing options.

Remember to import the stylesheet once somewhere in the client bundle:

import '@admmedia/eveplayer/style.css';