cookpete / react-player

A React component for playing a variety of URLs, including file paths, YouTube, Facebook, Twitch, SoundCloud, Streamable, Vimeo, Wistia and DailyMotion
https://cookpete.github.io/react-player
MIT License
9.44k stars 1.15k forks source link

import ReactPlayer from 'react-player/lazy' fails with vite #1443

Open DouglasDev opened 2 years ago

DouglasDev commented 2 years ago

Current Behavior

The app crashes with the following error:

Uncaught Error: Element type is invalid. Received a promise that resolves to: [object Object]. Lazy element type must resolve to a class or function. at mountLazyComponent (react-dom_client.js?v=53134127:14671:17) at beginWork (react-dom_client.js?v=53134127:15653:22) at beginWork$1 (react-dom_client.js?v=53134127:18882:22) at performUnitOfWork (react-dom_client.js?v=53134127:18358:20) at workLoopSync (react-dom_client.js?v=53134127:18298:13) at renderRootSync (react-dom_client.js?v=53134127:18277:15) at recoverFromConcurrentError (react-dom_client.js?v=53134127:17900:28) at performConcurrentWorkOnRoot (react-dom_client.js?v=53134127:17848:30) at workLoop (react-dom_client.js?v=53134127:195:42) at flushWork (react-dom_client.js?v=53134127:174:22) mountLazyComponent @ react-dom_client.js?v=53134127:14671 beginWork @ react-dom_client.js?v=53134127:15653 beginWork$1 @ react-dom_client.js?v=53134127:18882 performUnitOfWork @ react-dom_client.js?v=53134127:18358 workLoopSync @ react-dom_client.js?v=53134127:18298 renderRootSync @ react-dom_client.js?v=53134127:18277 recoverFromConcurrentError @ react-dom_client.js?v=53134127:17900 performConcurrentWorkOnRoot @ react-dom_client.js?v=53134127:17848 workLoop @ react-dom_client.js?v=53134127:195 flushWork @ react-dom_client.js?v=53134127:174 performWorkUntilDeadline @ react-dom_client.js?v=53134127:382 Show 11 more frames

Expected Behavior

I expect the video to load

Steps to Reproduce

  1. Download my minimal example: https://github.com/DouglasDev/vite-react-player-bug
  2. run npm i
  3. run npm run dev
  4. The app will crash

Environment

cookpete commented 2 years ago

It seems like my implementation of lazy loading players is prone to errors. I am open to better suggestions.

Would it be better to just have a component that accepts a players array and you just import anything that you need? eg:

import ReactPlayerCustom from 'react-player/custom'
import Youtube from 'react-player/youtube'
import Facebook from 'react-player/facebook'

<ReactPlayerCustom players={[Youtube, Facebook]} etc etc />
DouglasDev commented 2 years ago

I think the current api is good. I have an app where a user can enter any video url so it would be good if react player could automatically figure out which player to load (like it's doing now) since I can't know in advance. If I have time today, maybe I can figure out what the actual cause of the error is and open a PR.

cmaerz commented 2 years ago

@cookpete That looks great. We import everything cause of that problem, but only use file with hls at radio.net. Also disableDeferredLoading should be documented. :)

cookpete commented 2 years ago

@cmaerz I have to ask… why not just use hls.js directly instead of importing this whole library?

cmaerz commented 2 years ago

@cookpete We mostly play radio streams i guess that mostly uses either just the file player or the hls player. I had problems with just importing the file player, but tbh I don't really know why.

DouglasDev commented 2 years ago

@cookpete Haven't had time to write a fix but I think the issue is that vite uses native ESM imports whereas ReactPlayer appears to use ESM in the source code but exports CommonJS in the npm package. So I think just adding an untransformed ESM version to the npm package would fix the bug.

mpech commented 2 years ago

If it may help, problem stems from dynamic imports of players/index

var _default = [{
  key: "youtube",
  name: "YouTube",
  canPlay: _patterns.canPlay.youtube,
  lazyPlayer: (0, _react.lazy)(function() {
    return import(
      /* webpackChunkName: 'reactPlayerYouTube' */
      "./YouTube-PILJPAEI.js"
    ).then(m => {
      console.log('lazy vite')
      /*
        Here in vite, m is a module
        m.default contains { default: fn, __esModule: true }

        in wp, returning m is ok, in vite it is not
      */
      // below fix for vite
      return m.default
    });
  })
}

A workaround would be e.g to lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerYouTube' */'./YouTube').then(m => m.default.default ? m.default : m))

pretty much what does

function _interopRequireDefault(obj) {
  return obj && obj.__esModule ? obj : { "default": obj };
}

This feels a lot intrusive in source code so I guess an esm export would be preferrable (as @DouglasDev suggested)?

alexnault commented 2 years ago

We are also facing the same issue with Vite in dev (esbuild). I think an ESM export would be the best way forward too.

mutheusalmeida commented 2 years ago

I'm getting the same error. Anyone with a solution?

LWest001 commented 1 year ago

I'm still having this issue using React Player in an app that builds with Vite. App crashes in dev but works in production using react-player/lazy. Is there a workaround for this?

GabrielCousin commented 1 year ago

Hi @cookpete! Do you think we could reopen this issue (at least for clarity sake)? Thank you so much!

martavis commented 1 year ago

I also have this issue. For now, we're not using lazy but we definitely experienced the crash after moving to Vite from CRA.

pedrosousa13 commented 1 year ago

Would using @loadable/component be interesting in this case instead of lazy? I tried locally and it seems to work.

OciepaJakub commented 7 months ago

Maybe it's a little bit too late but in my case the import of lazy component throw general error about not found the start template. I realizied the solution:

import { Suspense, lazy, useEffect, useState } from 'react' import { BaseReactPlayerProps } from 'react-player/base' ` const Loader = () => { return (

)

} `

const VideoPlayer = (props: BaseReactPlayerProps) => { const [Component, setComponent] = useState<React.ComponentType<BaseReactPlayerProps> | null>(null);

useEffect(() => {
    setComponent(() => lazy(() => import('react-player/lazy')))
}, [])

if (!Component) {
    return <Loader />;
}

return (
    <Suspense fallback={<Loader />}>
        <Component {...props} />
    </Suspense>
)

}

export default VideoPlayer;

I've used node 20.x, vite 5.0, react 18.2, react-player 2.16.0, together with the Laravel / Inertia stack. Hope this would help someone.

luwes commented 7 months ago

this should be fixed in v3.0.0-canary.3 https://www.npmjs.com/package/react-player/v/3.0.0-canary.3 https://codesandbox.io/p/devbox/react-player-vite-6n78q7

note that this version has only ESM builds for now, we are testing if CJS or IIFE is actually still needed.

romankoho commented 2 months ago

@luwes any idea why my import/linter shows an error after updating to v3.0.0-canary.3?

import ReactPlayer from 'react-player/lazy'

ESLint: Unable to resolve path to module 'react-player/ lazy'.(import/ no-unresolved)