vime-js / vime

Customizable, extensible, accessible and framework agnostic media player. Modern alternative to Video.js and Plyr. Supports HTML5, HLS, Dash, YouTube, Vimeo, Dailymotion...
https://vimejs.com
MIT License
2.77k stars 152 forks source link

Example of how to use VimeJS with Sapper / Svelte Kit #168

Open antony opened 3 years ago

antony commented 3 years ago

Documentation

SSR Examples for new Vime JS.

Documentation page URL: Does not yet exist

Reason: The only existing "documentation" around this is the final comment on https://github.com/vime-js/vime/issues/38 - using dynamic imports is easy, but then you have to also use svelte:component in order to use those dynamic modules, and even then there are loads of console errors during build:

The 'this' keyword is equivalent to 'undefined' at the top level of an ES module, and has been rewritten
1: var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
                    ^
2:     function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3:     return new (P || (P = Promise))(function (resolve, reject) {
The 'this' keyword is equivalent to 'undefined' at the top level of an ES module, and has been rewritten
1: var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
                            ^
2:     function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3:     return new (P || (P = Promise))(function (resolve, reject) {

It would be good to have a written example of using the new "web components" based VimeJS, as I can't see a clear path forward for using it in an SSR enabled environment.

benbucksch commented 3 years ago

I think the problem is coming from using "Web components", which is a alternative technology to Svelte. In a real Svelte component, the problem does not appear, because there is no extends HTMLElement and browser-related code can run in onMount, which side-steps the issue.

tw1t611 commented 3 years ago

I really don't understand why anyone should go for web components. They have been risen and fallen with polymer. Like no major web framework uses them. Simple bundled Modules are just way more hassle-free and work everywhere. Nonetheless, is there any way to get it working with svelte-kit? It's in beta for a while now and I think nobody will start a new project with plain svelte anymore. So it is a very relevant issue.

mihar-22 commented 3 years ago

Web components have definitely had a bumpy ride and there are many negative things that can be said, but it's a standard none the less and it's where my focus is. There's been amazing improvements in browser support for enabling SSR with web components such as the new Declarative Shadow DOM API. There's also a bunch of other exciting proposals in the pipeline (eg: Constructable Stylesheets and HTML Modules).

Polymer has morphed into Lit and Google has recently released Lit 2 which has seen amazing adoption. Google has doubled down on it, and lot of major platforms/apps are shifting in this same direction. If I want to author a library that is framework agnostic and future proof then it can't be written at the framework layer (whatever the flavour of the month is or what you might think is the best). I'm also aware the Svelte can compile down to web components and I love the DX (huge Svelte fan)... but there are many issues with a compiled set of web components that we've experienced at work (this applies to Stencil as well).

I completely acknowledge that the integration packages were unfortunately not well written in Vime but I'm rectifying a lot of that on the new media player I'm working on which I'll announce soon. Framework support will hopefully come directly from Lit directly as they already support React.

I'm completely aware svelte-kit is the future of Svelte and I'm definitely looking to add better support. Please keep in mind that this is worked on mostly in spare time outside of work/family/life. I don't have the bandwidth to address a lot of issues with Vime at this time. There are great things in the works, just a little patience and I'll get there.

Thanks!

silllli commented 3 years ago

But despite these errors / warnings during compilation, Vime works with Sapper when dynamically imported and used with <svelte:component>, as far as I can tell. Or are there problems further down the line?

benbucksch commented 3 years ago

@silllli : Do you have a shortened code example of how you use <svelte:component>? That might be helpful for us.

silllli commented 3 years ago

Sure:

<script>
  import { onMount } from 'svelte';

  let Player;
  let Video;

  onMount(async () => {
    // NOTE: parentheses turn destructuring assignments into expressions
    ({ Player, Video } = await import('@vime/svelte'));
  });
</script>

<svelte:component this={Player} controls>
  <svelte:component this={Video} crossorigin="">
    <source data-src="file.mp4">
  </svelte:component>
</svelte:component>
stolinski commented 3 years ago

The above code works great for me in dev mode, but running build gives a

HTMLElement is not defined ReferenceError: HTMLElement is not defined

Any ideas? I can provide a repro if needed.

stolinski commented 3 years ago

Seems like my issue might be with Vite/SvelteKit eagerly bundling https://github.com/sveltejs/kit/issues/1570

silllli commented 3 years ago

Arguments to <svelte:component this={Player}> don’t seem to get passed correctly (at least autoplay doesn’t). 😢

benaltair commented 3 years ago

While trying to embed a Vimeo video on Kit 115 I get the following error:

ReferenceError: HTMLElement is not defined
    at /node_modules/@vime/core/dist/custom-elements/index.js?v=e741b189:826:14
    at instantiateModule (D:\Github\conference\node_modules\vite\dist\node\chunks\dep-bc228bbb.js:68693:166)

I agree that supporting Kit more thoroughly would be a good move given the direction of the project.

benwoodward commented 3 years ago

Damn, really disappointed this fantastic lib doesn't work with SvelteKit. Just got the HTMLElement is not defined error after following the Getting Started / Hls instructions in the docs.

EDIT: Actually, seems to work using the <svelte:component> workaround..

EDIT: Here's my working code for anyone struggling:

<script>
  import { onMount } from 'svelte';

  let isMounted = false;
  let video;
  let Player;
  let Hls;

  onMount(async () => {
    const vime = await import('@vime/svelte');
    Player = vime.Player;
    Hls = vime.Hls;
    isMounted = true;

    setTimeout(() => {
      video.play();
    }, 100);
  })
</script>

{#if isMounted === true}
  <svelte:component this={Player} bind:this={video} controls>
    <svelte:component this={Hls} version="latest" config={hlsConfig} crossorigin="">
      <source data-src="https://stream.mux.com/abc123.m3u8" type="application/x-mpegURL">
    </svelte:component>
  </svelte:component>
{/if}

SvelteKit: 1.0.0-next.116 Svelte: 3.38.3

EDIT: I'm experiencing issues calling methods on the Player using <svelte:component>:

index.js?v=188b6dfd:2980 Uncaught (in promise) TypeError: fullscreen error
    at Object.requestFullscreen (index.js?v=188b6dfd:2980)
    at FullscreenController.makeEnterFullscreenRequest (index.js?v=188b6dfd:3078)
    at FullscreenController.requestFullscreen (index.js?v=188b6dfd:3075)
    at HTMLElement.enterFullscreen (index.js?v=188b6dfd:5233)
    at proxy.enterFullscreen (Player.svelte? [sm]:93)

😞

EDIT: Hm, actually finding that I'm able to get it work without <svelte:component>:

<script>
  import { onMount } from 'svelte';

  let isMounted = false;
  let video;
  let Player;
  let Hls;

  onMount(async () => {
    const vime = await import('@vime/svelte');
    Player = vime.Player;
    Hls = vime.Hls;
    isMounted = true;

    setTimeout(() => {
      video.play();
    }, 100);
  })
</script>

{#if isMounted === true}
  <Player this={Player} bind:this={video} controls>
    <Hls this={Hls} version="latest" config={hlsConfig} crossorigin="">
      <source data-src="https://stream.mux.com/abc123.m3u8" type="application/x-mpegURL">
    </Hls>
  </Player>
{/if}

With this code I'm finding that video.play(), video.enterFullscreen() etc. are actually working. ..Although I can't set props on it:

Player.svelte? [sm]:125 Uncaught Error: <Player>: Props cannot be set directly on the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'
    at Player.set currentTime [as currentTime] (Player.svelte? [sm]:125)
    at proxy.set (proxy.js:110)

EDIT: Okay, so it actually works fine as a Web Component:

<script context="module">
  let player = null;

  export function pause() {
    player.pause();
  }
</script>

<script>
  // deps
  import { onMount } from 'svelte';

  // stores
  import { currentTimeSec, isPlaying } from '$lib/stores/media.js';

  $: if ($isPlaying) {
    if (player !== null) {
      player.play()
    }
  } else {
    if (player !== null) {
      player.pause()
    }
  }

  function handleTimeUpdate(event) {
    currentTimeSec.set(event.detail)
  }

  function movePlayheadToTime(time) {
    player.currentTime = time;

    if (!$isPlaying) {
      currentTimeSec.set(time)
    }
  }

  function setPlaybackRate(playbackRate) {
    player.playbackRate = playbackRate;
  }

  let hlsConfig = {};

  onMount(async () => {
    player = document.querySelector('vm-player');
  })
</script>

<div id="container">
  <vm-player playsinline on:vmCurrentTimeChange={handleTimeUpdate}>
    <vm-hls
      cross-origin="true"
      poster="https://image.mux.com/muxid-123/thumbnail.png?width=214&height=121&fit_mode=pad">
      <source data-src="https://stream.mux.com/muxid-123.m3u8" type="application/x-mpegURL" />
    </vm-hls>
    <vm-default-ui></vm-default-ui>
  </vm-player>
</div>

app.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="/favicon.ico" />
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/@vime/core@^5/themes/default.css"
      />
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/@vime/core@^5/themes/light.css"
      />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script
      defer
      type="module"
      src="https://cdn.jsdelivr.net/npm/@vime/core@^5/dist/vime/vime.esm.js"
      >
    </script>
    %svelte.head%
  </head>
  <body class="text-gray-300">
    <div id="svelte">%svelte.body%</div>
  </body>
</html>
llamaswize commented 3 years ago

Which is the official recommended way to implement Vime on a SvelteKit project? Can we rise a feature request for SvelteKit support? At least add some kind of mention of SvelteKit on the documentation.

stolinski commented 3 years ago

We have it working in SvelteKit by using the web component version and just loading the script.

ralyodio commented 3 years ago

why are the docs trash for svelte? can someone post an official solution here?

stolinski commented 3 years ago

why are the docs trash for svelte? can someone post an official solution here?

The docs are for Svelte. Svelte Kit renders on the server, so it won't work the same. This is an open source project that I'm sure is a ton of work to maintain. No need to be rude. As I stated in my previous comment, that was trying to be helpful, if you use the web components version, it works without issue. I'm sure the maintainers would love a PR if you have time to update the docs.

louishuddleston commented 3 years ago

Here's how I've got Vime working with SvelteKit using @vime/core

<script>
  import { onMount } from 'svelte';

  export let src;
  let showPlayer = false;
  let player;

  onMount(async () => {
    const { defineCustomElements } = await import('@vime/core');
    defineCustomElements();
    showPlayer = true;
  });
</script>

{#if showPlayer}
  <vm-player bind:this={player}>
    <vm-video>
      <source data-src={src} type="video/mp4" />
    </vm-video>
    <vm-ui>
      <vm-default-controls />
    </vm-ui>
  </vm-player>
{/if}

@sveltejs/kit@1.0.0-next.180 @vime/core@5.0.33 svelte@3.43.1

YugoCode commented 2 years ago

Did someone get it working on sveltekit with the svelte bindings (@vime/svelte)?

benwoodward commented 2 years ago

Hi @mihar-22, will Vidstack be available as an importable component in Svelte?

mihar-22 commented 2 years ago

Hey @benwoodward! We're going to start out with recommending web components for Svelte to reduce the initial workload and maintenance burden (espescially when it comes to documentation). Based on feedback we can definitely consider exporting all elements as Svelte components.

Yakumwamba commented 2 years ago

Here's how I've got Vime working with SvelteKit using @vime/core

<script>
  import { onMount } from 'svelte';

  export let src;
  let showPlayer = false;
  let player;

  onMount(async () => {
    const { defineCustomElements } = await import('@vime/core');
    defineCustomElements();
    showPlayer = true;
  });
</script>

{#if showPlayer}
  <vm-player bind:this={player}>
    <vm-video>
      <source data-src={src} type="video/mp4" />
    </vm-video>
    <vm-ui>
      <vm-default-controls />
    </vm-ui>
  </vm-player>
{/if}

@sveltejs/kit@1.0.0-next.180 @vime/core@5.0.33 svelte@3.43.1

Thanks this really help solve my issue. Vime player does not work in .svelte if you do an import.

Nisthar commented 2 years ago
<script>
  import { onMount } from 'svelte';

  export let src;
  let showPlayer = false;
  let player;

  onMount(async () => {
    const { defineCustomElements } = await import('@vime/core');
    defineCustomElements();
    showPlayer = true;
  });
</script>

{#if showPlayer}
  <vm-player bind:this={player}>
    <vm-video>
      <source data-src={src} type="video/mp4" />
    </vm-video>
    <vm-ui>
      <vm-default-controls />
    </vm-ui>
  </vm-player>
{/if}

does it mean i can't use this code inside a .svelte file? where else would you use it?

louishuddleston commented 2 years ago
<script>
  import { onMount } from 'svelte';

  export let src;
  let showPlayer = false;
  let player;

  onMount(async () => {
    const { defineCustomElements } = await import('@vime/core');
    defineCustomElements();
    showPlayer = true;
  });
</script>

{#if showPlayer}
  <vm-player bind:this={player}>
    <vm-video>
      <source data-src={src} type="video/mp4" />
    </vm-video>
    <vm-ui>
      <vm-default-controls />
    </vm-ui>
  </vm-player>
{/if}

does it mean i can't use this code inside a .svelte file? where else would you use it?

You should be able to use it in a .svelte file

Nisthar commented 2 years ago

@louishuddleston

You should be able to use it in a .svelte file

is there a way to change the width/height of the player?

multiplehats commented 2 years ago

Sure:

<script>
  import { onMount } from 'svelte';

  let Player;
  let Video;

  onMount(async () => {
    // NOTE: parentheses turn destructuring assignments into expressions
    ({ Player, Video } = await import('@vime/svelte'));
  });
</script>

<svelte:component this={Player} controls>
  <svelte:component this={Video} crossorigin="">
    <source data-src="file.mp4">
  </svelte:component>
</svelte:component>

This worked wonderfully for me, thank you!

<script lang="ts">
    import { onMount } from 'svelte';

    export let videoId: number | null = 0;

    let Player: any = null;
    let Vimeo: any = null;

    onMount(async () => {
        // NOTE: parentheses turn destructuring assignments into expressions
        ({ Player, Vimeo } = await import('@vime/svelte'));
    });

    // set to 0 in case it's null and let the vimeo player handle cases where there's no video
    $: videoId = videoId || 0;
</script>

<svelte:component this={Player} controls>
    <svelte:component this={Vimeo} videoId={videoId} />
</svelte:component>