From f51575ee7462ebbcca1c812fff5162a92bdef01c Mon Sep 17 00:00:00 2001 From: Colby Fayock Date: Mon, 24 Apr 2023 20:39:46 -0400 Subject: [PATCH 1/7] importing the npm module dynamically on client --- next-cloudinary/package.json | 3 +- .../CldVideoPlayer/CldVideoPlayer.tsx | 123 +++-- next-cloudinary/src/types/player.ts | 3 +- yarn.lock | 519 +++++++++++++++++- 4 files changed, 584 insertions(+), 64 deletions(-) diff --git a/next-cloudinary/package.json b/next-cloudinary/package.json index c88f7ce7..9e16718c 100644 --- a/next-cloudinary/package.json +++ b/next-cloudinary/package.json @@ -16,7 +16,8 @@ "dependencies": { "@cloudinary-util/url-loader": "^3.1.1", "@cloudinary-util/util": "^2.0.1", - "@cloudinary/url-gen": "^1.8.6" + "@cloudinary/url-gen": "^1.8.6", + "cloudinary-video-player": "^1.9.9" }, "devDependencies": { "@babel/core": "^7.19.6", diff --git a/next-cloudinary/src/components/CldVideoPlayer/CldVideoPlayer.tsx b/next-cloudinary/src/components/CldVideoPlayer/CldVideoPlayer.tsx index 720acb89..e2757560 100644 --- a/next-cloudinary/src/components/CldVideoPlayer/CldVideoPlayer.tsx +++ b/next-cloudinary/src/components/CldVideoPlayer/CldVideoPlayer.tsx @@ -1,17 +1,10 @@ -import React, { useRef, MutableRefObject } from 'react'; -import Script from 'next/script'; +import React, { useRef, useEffect, useState, MutableRefObject, } from 'react'; import Head from 'next/head'; import { CldVideoPlayerProps } from './CldVideoPlayer.types'; import { CloudinaryVideoPlayer, CloudinaryVideoPlayerOptions, CloudinaryVideoPlayerOptionsLogo } from '../../types/player'; const CldVideoPlayer = (props: CldVideoPlayerProps) => { - // If no ID is passed in - we want to be able to ensure that we are using - // unique IDs for each player. We can do this by generating a random number - // and using that as the ID. We use a ref here so that we can ensure that - // the ID is only generated once. - const idRef = useRef(Math.ceil(Math.random() * 100000)); - const { autoPlay = 'never', colors, @@ -36,14 +29,11 @@ const CldVideoPlayer = (props: CldVideoPlayerProps) => { // Setup the refs and allow for the caller to pass through their // own ref instance - const cloudinaryRef = useRef(); const defaultVideoRef = useRef() as MutableRefObject; const videoRef = props.videoRef || defaultVideoRef; const defaultPlayerRef = useRef()as MutableRefObject; const playerRef = props.playerRef || defaultPlayerRef; - const playerId = id || `player-${src.replace('/', '-')}-${idRef.current}`; - const events: Record = { error: onError, loadeddata: onDataLoad, @@ -53,64 +43,83 @@ const CldVideoPlayer = (props: CldVideoPlayerProps) => { ended: onEnded }; - /** - * handleEvent - * @description Event handler for all player events - */ - - function handleEvent(event: { type: 'string' }) { - const activeEvent = events[event.type]; + let logoOptions: CloudinaryVideoPlayerOptionsLogo = {}; - if ( typeof activeEvent === 'function' ) { - activeEvent(getPlayerRefs()); + if ( typeof logo === 'boolean' ) { + logoOptions.showLogo = logo; + } else if ( typeof logo === 'object' ) { + logoOptions = { + ...logoOptions, + showLogo: true, + logoImageUrl: logo.imageUrl, + logoOnclickUrl: logo.onClickUrl } } - /** - * handleOnLoad - * @description Stores the Cloudinary window instance to a ref when the widget script loads - */ + let playerOptions: CloudinaryVideoPlayerOptions = { + autoplayMode: autoPlay, + cloud_name: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME, + controls, + fontFace: fontFace || '', + loop, + muted, + publicId: src, + secure: true, + ...logoOptions + }; - function handleOnLoad() { - if ( 'cloudinary' in window ) { - cloudinaryRef.current = window.cloudinary; + if ( typeof colors === 'object' ) { + playerOptions.colors = colors; + } - let logoOptions: CloudinaryVideoPlayerOptionsLogo = {}; + // If no ID is passed in - we want to be able to ensure that we are using + // unique IDs for each player to avoid conflicts. We can do this by generating + // a random number and using that as the ID. We use a ref here so that we can + // ensure that the ID is only generated once. - if ( typeof logo === 'boolean' ) { - logoOptions.showLogo = logo; - } else if ( typeof logo === 'object' ) { - logoOptions = { - ...logoOptions, - showLogo: true, - logoImageUrl: logo.imageUrl, - logoOnclickUrl: logo.onClickUrl - } - } + const idRef = useRef(Math.ceil(Math.random() * 100000)); + const [playerId, setPlayerId] = useState(id); - let playerOptions: CloudinaryVideoPlayerOptions = { - autoplayMode: autoPlay, - cloud_name: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME, - controls, - fontFace: fontFace || '', - loop, - muted, - publicId: src, - secure: true, - ...logoOptions - }; - - if ( typeof colors === 'object' ) { - playerOptions.colors = colors; - } + useEffect(() => { + if ( typeof id !== 'undefined' ) return; + setPlayerId(`player-${src.replace('/', '-')}-${idRef.current}`); + }, []) + + // Initialize the player + + useEffect(() => { + if ( !playerId ) return; + + (async function run() { + // @ts-ignore + const { videoPlayer } = await import('cloudinary-video-player'); - playerRef.current = cloudinaryRef.current.videoPlayer(videoRef.current, playerOptions); + playerRef.current = videoPlayer(videoRef.current, playerOptions); Object.keys(events).forEach((key) => { if ( typeof events[key] === 'function' ) { playerRef.current?.on(key, handleEvent); } }); + })(); + + return () => { + if ( playerRef.current ) { + playerRef.current.dispose(); + } + } + }, [playerId]) + + /** + * handleEvent + * @description Event handler for all player events + */ + + function handleEvent(event: { type: 'string' }) { + const activeEvent = events[event.type]; + + if ( typeof activeEvent === 'function' ) { + activeEvent(getPlayerRefs()); } } @@ -138,12 +147,6 @@ const CldVideoPlayer = (props: CldVideoPlayerProps) => { width={width} height={height} /> -