React-player: Feature request: lazy players

Created on 5 Nov 2019  Â·  18Comments  Â·  Source: cookpete/react-player

Motivation: On my page I don't know what player will be used in each particular case and many of the players will never be used, so I would like to lazily load only one player in each particular case.

Something like this:

import React, { Suspense, lazy } from 'react'
import { whichPlayerCanPlay } from 'react-player'

const players = {
  youtube: () => import('react-player/lib/players/YouTube'),
  vimeo: () => import('react-player/lib/players/Vimeo'),
  file: () => import('react-player/lib/players/FilePlayer')
}

const MyPlayer = (props) => {
  const { url } = props

  const playerName = whichPlayerCanPlay(url, { players: ['youtube', 'vimeo', 'file'] })

  if (!playerName) {
    return null
  }

  const LazyPlayer = lazy(players[playerName]);

  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyPlayer {...props} />
    </Suspense>
  )
}

The problem here is that the canPlay logic is inside of each individual player file and to know whether a player is capable of playing the url I need to download it. Could the canPlay logic be extracted from each individual player to a separate file?

Most helpful comment

This should be fixed in v2.0.1

All 18 comments

Hey @trurl-master, yeah this has been on my radar for a long time. It would reduce the bundle size massively and essentially render the single player imports redundant. I can look at implementing this, but don't have an exact timeline.

I've pushed my first attempt at this as an alpha version of 2.0.0 (as there are a few breaking changes). Try it out with:

npm install [email protected]

(as there are a few breaking changes)

Hi, @CookPete could you please let know what braking changes are in 2.0 version? I've successfully added the alpha version to my project and haven't spotted any breaking changes or problems yet.

@ramlez Namely the single player functionality eg

import YouTubePlayer from 'react-player/lib/players/YouTube'

becomes pretty much redundant, as only the Youtube player will be loaded if you only ever use a Youtube URL.

I should be able to get a bit closer to releasing this in the next couple of days.

I'm also considering removing the preload functionality and leaving it as a legacy feature in older versions – autoplay policies are making it redundant, and it's a fairly hacky feature anyway.

Hey @CookPete @trurl-master, until Suspense and lazy support SSR rendering, maybe you could consider using Loadable Components instead?

v2.0.0 is now here, which includes lazy loading players using lazy and Suspense. @dbismut unfortunately I had written all the lazy logic before your comment.

@dbismut Is there much benefit to including the lazy player code in SSR? Most of the time the only thing rendered is a single div or iframe, which is populated on the client when the third party player API loads.

@CookPete it's not so much that SSR actually makes sense in this case, but rather than using Suspense and lazy will break SSR. In other words, if you have a look at this sandbox using Gatsby, and if you try to build it, you will have the following error.

image

... which redirects to this page: https://reactjs.org/docs/error-decoder.html/?invariant=294

Let me know if you prefer that I open a separate issue for this, as someone will open it sooner or later.

^ i also had the above issue, wondering what to do about it...

Is there a quick fix for Suspense to just not render anything during SSR, rather than breaking things? This seems like a stupid problem to have when ReactPlayer doesn’t really benefit from rendering anything on the server.

Well, I guess you could detect if you're server-side:

const isBrowser = (typeof window !== 'undefined' && window.document)
return <div>{ isBrowser && <Suspense /> }</div>

It's also breaking my Gatsby build with the same exact error posted by @dbismut. Wondering exactly how to get around this?

@ericnation I downgraded to 1.15.3...that fixed the build and got me past this issue, but I don't really need any of these lazy/suspense features, so YMMV.

@ericnation I guess you can use the method mentioned by @dbismut to get rid of the build-time problem.

   const isBrowser = (typeof window !== 'undefined' && window.document)
   ...
   <>
     { isBrowser && <ReactPlayer></ReactPlayer>}
  </>

Just wonder if (typeof window !== 'undefined' && window.document) would be included in react-player?

Just wonder if (typeof window !== 'undefined' && window.document) would be included in react-player?

That’s the idea indeed!

This should be fixed in v2.0.1

Can you add this to the docs? Im trying to figure out how to improve load time.

Note that from v2.2.0, the lazy loading version of ReactPlayer has moved to react-player/lazy. See MIGRATING.md for more info.

I'm not considering it a breaking change as things won't actually break – the only impact will be a slightly bigger bundle size until you start importing from react-player/lazy.

I've added clarification to the readme to only use it if your build pipeline supports dynamic import() statements.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pwbrown picture pwbrown  Â·  8Comments

intelligence picture intelligence  Â·  3Comments

wmertens picture wmertens  Â·  7Comments

MDrooker picture MDrooker  Â·  6Comments

rockmandash picture rockmandash  Â·  5Comments