vime icon indicating copy to clipboard operation
vime copied to clipboard

Example of how to use VimeJS with Sapper / Svelte Kit

Open antony opened this issue 3 years ago • 24 comments

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.

antony avatar Feb 03 '21 17:02 antony

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.

benbucksch avatar May 07 '21 17:05 benbucksch

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.

tw1t611 avatar Jun 03 '21 07:06 tw1t611

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!

mihar-22 avatar Jun 03 '21 12:06 mihar-22

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?

silllli avatar Jun 07 '21 09:06 silllli

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

benbucksch avatar Jun 07 '21 15:06 benbucksch

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>

silllli avatar Jun 07 '21 15:06 silllli

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 avatar Jun 08 '21 22:06 stolinski

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

stolinski avatar Jun 08 '21 23:06 stolinski

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

silllli avatar Jun 09 '21 17:06 silllli

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.

benaltair avatar Jun 20 '21 09:06 benaltair

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>

benwoodward avatar Jun 28 '21 09:06 benwoodward

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.

llamaswize avatar Aug 24 '21 22:08 llamaswize

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

stolinski avatar Aug 24 '21 22:08 stolinski

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

ralyodio avatar Oct 07 '21 00:10 ralyodio

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.

stolinski avatar Oct 07 '21 01:10 stolinski

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/[email protected] @vime/[email protected] [email protected]

louishuddleston avatar Oct 25 '21 17:10 louishuddleston

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

YugoCode avatar Jan 23 '22 11:01 YugoCode

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

benwoodward avatar Feb 16 '22 03:02 benwoodward

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.

mihar-22 avatar Feb 16 '22 03:02 mihar-22

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/[email protected] @vime/[email protected] [email protected]

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

Yakumwamba avatar Feb 24 '22 04:02 Yakumwamba

<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?

Nisthar avatar May 04 '22 12:05 Nisthar

<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

louishuddleston avatar May 04 '22 12:05 louishuddleston

@louishuddleston

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

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

Nisthar avatar May 05 '22 19:05 Nisthar

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>

multiplehats avatar May 16 '22 19:05 multiplehats