Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: CI

on:
push:
branches: [master]
pull_request:

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node: [22, 24]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: ${{ matrix.node }}
cache: npm
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm pack --dry-run
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24
51 changes: 51 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Changelog

This file lists the changes of version 2.x (Vue 3). Version 1.x (Vue 2) is on the `1x` branch.

## 2.5.0

### Added

- TypeScript types for the props, the sources, the events, the player methods and the plugin ([#2](https://github.com/avidofood/vue-responsive-video-background-player/issues/2)). The types also register `VideoBackground` as a global component for template type checks. If you added a `declare module` file for this package, you can delete it.
- `stop()` on the player: it pauses the video and goes back to the start ([#30](https://github.com/avidofood/vue-responsive-video-background-player/issues/30)).
- The `error` event carries the error event of the video or the error of `play()`.
- `play()` on the player returns a promise.

### Fixed

- Server-side rendering, for example with Nuxt, works without a hydration mismatch ([#39](https://github.com/avidofood/vue-responsive-video-background-player/issues/39), [#28](https://github.com/avidofood/vue-responsive-video-background-player/issues/28)). The server renders the video without a source, and the browser adds the right video after hydration. Before, the server rendered the source for a 0px window, and the browser started to load that video.
- The browser can block playback, for example on iOS in Low Power Mode or for a video with sound. Then the poster stays visible and the component emits `error`. Before, the component showed a stopped video and emitted `playing`.
- The component emits `playing` after playback really started.
- If the video file fails to load, for example on a 404, the component emits `error`. Before, the browser fired that error on the `<source>` element, and the component did not see it.
- The fade-in transition works again. Vue 3 renamed the class `fade-enter` to `fade-enter-from`.
- The `type` attribute of the source is only set for known file extensions. Before, a URL such as `video.mp4?v=1.2` got the type `video/2`, and the browser skipped the video.
- On unmount, the component removes its resize listener.
- The component no longer sorts the `sources` array of the parent in place.
- A source change shortly before unmount no longer throws a `TypeError`. Fast source changes load only the last source.
- The `ready` event fires once for each loaded video. Before, a `canplay` event after buffering paused the video again, and with `autoplay` set to `false` the video stayed paused.
- The internal pause before autoplay no longer emits `paused`.
- The private method `$_innerWidth` is now `_innerWidth`, as the notes of 2.4.0 already said.

### Changed

- `vue` (`^3.2.0`) is now a peer dependency. Before, it was only a dev dependency, so npm did not check the Vue version.
- The package declares `"type": "commonjs"` and `"exports"` with `types` conditions. The file names in `dist/` are unchanged.
- The build uses Vite 8. Tests use Vitest. The development tools need Node.js 22.12 or newer. The published files have no Node.js requirement.
- The `publish` script is removed. npm ran it after every `npm publish`, so it started a second publish. `npm pack` and `npm publish` now build `dist/` first (`prepack`).

## 2.4.1

- Package metadata update. No code change.

## 2.4.0

- **Breaking Change**: Removed `$` prefix from private methods to prevent potential conflicts with other libraries (for example jQuery).
The following methods are renamed:
- `$_change_video_resolution` → `_change_video_resolution`
- `$_innerWidth` → `_innerWidth` (this rename only took effect in 2.5.0)

If you were using these methods in your project, please update your code accordingly.

- Improved compatibility with legacy code and projects using jQuery.
- New `paused` event ([#43](https://github.com/avidofood/vue-responsive-video-background-player/pull/43)).
- New props `objectPosition` and `posterBgSize` ([#45](https://github.com/avidofood/vue-responsive-video-background-player/pull/45)).
158 changes: 109 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,78 @@

**If you are looking to play videos in the background, you've found the right Vue package! 😜 (Heads up: No YouTube videos... yet!)**

>**Prerequisites**: Vue 2.x.x or Vue 3.x.x
>**Prerequisites**: Vue 3.2 or newer for version 2.x of this package. For Vue 2, use version 1.x.

## Installation in 2 Steps

### 1: Add with npm 💻
```bash
# For Vue 2.x.x
npm install vue-responsive-video-background-player@1.3.1

# For Vue 3.x.x
npm install vue-responsive-video-background-player
npm install vue-responsive-video-background-player

# For Vue 2.x.x
npm install vue-responsive-video-background-player@1x
```

### 2a: Import the component

```vue
<script setup>
import VideoBackground from 'vue-responsive-video-background-player';
</script>
```

### 2a: Install as a component
Or register it globally:

```javascript
import VideoBackground from 'vue-responsive-video-background-player'
import { createApp } from 'vue';
import VideoBackground from 'vue-responsive-video-background-player';

Vue.component('video-background', VideoBackground);
const app = createApp(App);
app.component('VideoBackground', VideoBackground);
```
### 2b: Install as a plugin

### 2b: Install as a plugin
```javascript
import { Plugin } from 'vue-responsive-video-background-player'
import { createApp } from 'vue';
import { Plugin } from 'vue-responsive-video-background-player';

const app = createApp(App);
app.use(Plugin);
```

The plugin registers the component as `VideoBackground`. You can use it as `<VideoBackground>` or `<video-background>`.

### (3: Only for Nuxt users)

#### Nuxt 3 and Nuxt 4

Vue.use(Plugin);
Since version 2.5.0 the component works with server-side rendering. Create a plugin file, for example `plugins/video-background.ts`:

```javascript
import { Plugin } from 'vue-responsive-video-background-player';

export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(Plugin);
});
```

Then use the `<video-background>` tag in any page. The server renders the section, the poster, the overlay and your slot content. The server does not know the window width, so the browser adds the video after hydration.

The component injects its CSS with JavaScript. Until the JavaScript runs, the page shows the server HTML without these styles. If you prefer to render the component only in the browser, name the plugin file `video-background.client.ts` and wrap the component in `<ClientOnly>`:

```html
<ClientOnly>
<video-background src="/videos/hero.mp4" style="height: 100vh;" />
</ClientOnly>
```

### (3: Only for Nuxt.js users)
#### Nuxt.js v2.xx.x
A `.client` plugin alone is not enough: the server cannot resolve the component, and Vue reports a hydration mismatch.

#### Nuxt 2 (package version 1.x)
>Thanks to [@skoulix](https://github.com/avidofood/vue-responsive-video-background-player/issues/8#issuecomment-654821213) for his instructions:

Again this is only for Nuxt.js users. Gridsome users click [here](https://gridsome.org/docs/assets-scripts/#without-ssr-support). At your `nuxt.config.js` locate the part where you declare your plugins and import the file. Example:
Again this is only for Nuxt.js users. Gridsome users click [here](https://gridsome.org/docs/assets-scripts/#without-ssr-support). At your `nuxt.config.js` locate the part where you declare your plugins and import the file. Example:

```
plugins: [
Expand All @@ -58,23 +98,18 @@ plugins: [

Now the component is globally available and can be used at any .vue file without issues.

#### Nuxt.js v3.xx.x
>Thanks to [@Vertenz](https://github.com/avidofood/vue-responsive-video-background-player/issues/8#issuecomment-1192011721) for his instructions:
### TypeScript

for NUXT 3 I used directive to make it work. Create **plugins** directory then add **video-bg.client.ts** _(or any name but **.client** is obligatory for client side render, cause you don't have the window at ssr)_ file with
Since version 2.5.0 the package contains type declarations for the props, the events, the player methods and the plugin. If you added a `declare module 'vue-responsive-video-background-player'` file for older versions, you can delete it.

```
import { defineNuxtPlugin } from "#app";
import { Plugin } from "vue-responsive-video-background-player";
```typescript
import type { VideoBackgroundSource } from 'vue-responsive-video-background-player';

export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(Plugin);
});
const sources: VideoBackgroundSource[] = [
{ src: '/videos/mobile.mp4', res: 638, autoplay: true },
];
```

then you use the **video-background** tag


## Usage - (or to make it runnable 🏃‍♂️)


Expand Down Expand Up @@ -120,14 +155,17 @@ This package is for responsive videos depicting different video resolution. Have

This is your path to your video. You can just use this value for showing your video in every resolution.

>**Warning** for [Vue CLI](https://cli.vuejs.org/guide/creating-a-project.html): You need to bind the source like this: ``:src="require(`@/assets/video/timelapse.mp4`)"``. [Read here why](https://github.com/avidofood/vue-responsive-video-background-player/issues/10#issuecomment-646959090)
>**Note** for Vite and Nuxt: Put the video in the `public` folder and use the path from the site root, for example `src="/videos/hero.mp4"`. Or import the file, for example `import heroVideo from '@/assets/hero.mp4'`, and bind it with `:src="heroVideo"`. With Vue CLI, bind it like this: ``:src="require(`@/assets/video/timelapse.mp4`)"``. [Read here why](https://github.com/avidofood/vue-responsive-video-background-player/issues/10#issuecomment-646959090)

The component sets the `type` attribute of the video for `.mp4`, `.m4v`, `.webm`, `.ogv`, `.ogg` and `.m3u8` files. For other URLs, for example a URL without a file extension, it sets no type, and the browser checks the file itself.

>**HLS** (`.m3u8`): Safari, iOS and some other browsers play HLS streams natively. The component does not include [hls.js](https://github.com/video-dev/hls.js), so other browsers do not play the stream.

- `poster` (default: `''`)

This is your first background image that is shown before the video is loaded.

>**Warning** for [Vue CLI](https://cli.vuejs.org/guide/creating-a-project.html): You need to bind the source like this: ``:src="require(`@/assets/img/logo.png`)"``. [Read here why](https://github.com/avidofood/vue-responsive-video-background-player/issues/10#issuecomment-646959090)
>**Note**: The same as for `src` applies. With Vue CLI, bind the image like this: ``:poster="require(`@/assets/img/logo.png`)"``.

- `sources` (default: `[]`)

Expand All @@ -152,15 +190,15 @@ If you love overlays, then copy the overlay from the advanced example.

- `muted` (default: `true`)

Warning. Videos are perhaps not played when unmuted.
Browsers block autoplay for most videos with sound. If the browser blocks the video, the poster stays visible and the component emits `error`.

- `loop` (default: `true`)

Loops through the video. You can catch the event `ended` to show only the poster.

- `preload` (default: `auto`)

https://www.w3schools.com/tags/att_video_preload.asp
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#preload

- `objectFit` (default: `cover`)

Expand All @@ -180,36 +218,66 @@ So the poster fits perfectly in the container

- `playsWhen` (default: `canplay`)

This is important, if you know that you might have users with bad internet speed, you should definetly use `canplaythrough`. Learn more in [video events](https://www.w3schools.com/tags/ref_av_dom.asp).
If some of your users have a slow connection, use `canplaythrough`. Learn more in [video events](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement#events).

- `playbackRate` (default: `1.0`)

The playbackRate property sets the current playback speed of the video. [Example](https://www.w3schools.com/jsref/prop_video_playbackrate.asp) but negative values didn't work for me?
The playbackRate property sets the current playback speed of the video. [Example](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/playbackRate) but negative values didn't work for me?

- `transition` (default: `fade`)

You can add your own transition styles here. If you set it to empty string, it won't show any transitions.
You can add your own transition styles here. If you set it to an empty string, the video shows without a transition.

The `fade` transition takes one second. For a different duration, give the transition your own name and add the CSS for it:

```html
<video-background src="/videos/hero.mp4" transition="slow-fade" />

<style>
.slow-fade-enter-active,
.slow-fade-leave-active {
transition: opacity 3s;
}
.slow-fade-enter-from,
.slow-fade-leave-to {
opacity: 0;
}
</style>
```

## Events

- `ready`: Video is loaded
- `ready`: Video is loaded. The event fires once for each video that loads.
- `playing`: Video is playing
- `paused`: Video is paused
- `error`: Video error
- `loading`: Video is loading
- `ended`: Video finished, only when `loop` is set to false
- `error`: The video failed, for example because the file is missing, or the browser blocked playback. The event carries the error event of the video or the error of `play()`. The poster stays visible.
- `loading`: A new video is loading, for example after a resize
- `ended`: Video finished. This event fires only with `loop` set to false.

## Methods

If you happen to need more control over the player, you can use the internal methods. For that, you need to set `ref=videobackground` to the HTML tag `<video-background>`. After that you can call all methods like this `this.$refs.videobackground.player.play()`.

- `play()`: Plays the video
- `play()`: Plays the video and returns a promise. The promise resolves after playback starts or after the browser blocks it.
- `pause()`: Pauses the video
- `stop()`: Pauses the video and goes back to the start. Call `play()` to start it again.
- `show()`: Shows the video
- `hide()`: Hides the video and shows the poster
- `load()`: Loads the video

- `load()`: Hides the video and loads it again after one second

## Development

You need Node.js 22.12 or newer (see `.nvmrc`).

```bash
npm install
npm test # unit tests and type checks
npm run lint
npm run build # builds dist/ and the demo
```

`npm pack` and `npm publish` build `dist/` first.

## Security

If you discover any security problems, please, don't email me. (I'm a bit scared 😱) avidofood@protonmail.com
Expand All @@ -225,12 +293,4 @@ Wow, you really read all that?! If you enjoyed this, hit the ⭐️ button to gi

## Changelog

### v2.4.0
- **Breaking Change**: Removed `$` prefix from private methods to prevent potential conflicts with other libraries (e.g., jQuery).
The following methods have been renamed:
- `$_change_video_resolution` → `_change_video_resolution`
- `$_innerWidth` → `_innerWidth`

If you were using these methods in your project, please update your code accordingly.

- Improved compatibility with legacy code and projects using jQuery.
See [CHANGELOG.md](CHANGELOG.md).
5 changes: 0 additions & 5 deletions babel.config.js

This file was deleted.

20 changes: 2 additions & 18 deletions demo/public/build/js/app.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions demo/resources/js/App.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<!-- eslint-disable max-len -->
<template>
<video-background
class="video-container"
Expand Down
3 changes: 0 additions & 3 deletions mix-manifest.json

This file was deleted.

Loading
Loading