How to make facades for YouTube videos in Nuxt and TailwindCSS to optimize page loading speed

Search for a command to run...

No comments yet. Be the first to comment.
Hello! I recently implemented Sitemap in Nuxt, including i18n (internationalization) and dynamic links. I didn't find any tutorial online about implementing a sitemap combining these options, so I hope this guide will help some other devs. Internatio...

Strapi CMS is an open-source content management system I implemented recently in one of my projects. Some parts of integrating Strapi with Nuxt were not well described, so I decided to share solutions I've done on my blog. Why preview? I work with so...
When you are about to embark on a journey to become a full stack developer, or you want to build web services on your own, there are many choices to be made. A lot of them depend on the services you want to build and your current knowledge. When I to...

I recently added a YouTube video to my page and it negatively affected my website Page Insights (PI) performance. One of the tips PI provided was to provide facades for the Youtube video links, to avoid loading them directly. I implemented it and it indeed improved my PI result and sped up the page load. Below is an overview of how to do it.
The facade is a thumbnail picture that looks like the actual video but only loads the actual component once the user
Mobile/Tablet:
Desktop
I found a couple of libraries online that do it, but none of them seemed to work for me, thus I decided to implement my own using Nuxt3 and TailwindCSS.
<template>
<div class="flex justify-center mt-5">
// DESKTOP
<!-- This padding-top gives a 16:9 aspect ratio -->
<div @mouseenter="showIframe = true"
class="hidden sm:block relative overflow-hidden w-full" style="padding-top: 56.25%;">
<!-- YOUTUBE SVG icon centered in front of the image -->
<svg v-if="!showIframe" xmlns="http://www.w3.org/2000/svg" width="4.25em" height="4.25em" viewBox="0 0 256 180"
class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-10">
<path fill="#f00"
d="M250.346 28.075A32.18 32.18 0 0 0 227.69 5.418C207.824 0 127.87 0 127.87 0S47.912.164 28.046 5.582A32.18 32.18 0 0 0 5.39 28.24c-6.009 35.298-8.34 89.084.165 122.97a32.18 32.18 0 0 0 22.656 22.657c19.866 5.418 99.822 5.418 99.822 5.418s79.955 0 99.82-5.418a32.18 32.18 0 0 0 22.657-22.657c6.338-35.348 8.291-89.1-.164-123.134" />
<path fill="#fff" d="m102.421 128.06l66.328-38.418l-66.328-38.418z" />
</svg>
<img v-if="!showIframe" :src="'https://img.youtube.com/vi/' + extractYouTubeID(sanitizedLink) + '/maxresdefault.jpg'"
class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 object-cover w-full h-full" />
<iframe v-if="showIframe" :src="YOUTUBE_LINK" title="YouTube video player" frameborder="0"
allowfullscreen class="absolute top-0 left-0 w-full h-full"></iframe>
</div>
// MOBILE
<div @click="showIframe = true" class="block sm:hidden relative overflow-hidden w-5/6"
style="padding-top: 56.25%;">
<!-- YOUTUBE SVG icon centered in front of the image -->
<svg v-if="!showIframe" xmlns="http://www.w3.org/2000/svg" width="4.25em" height="4.25em" viewBox="0 0 256 180"
class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-10">
<path fill="#f00"
d="M250.346 28.075A32.18 32.18 0 0 0 227.69 5.418C207.824 0 127.87 0 127.87 0S47.912.164 28.046 5.582A32.18 32.18 0 0 0 5.39 28.24c-6.009 35.298-8.34 89.084.165 122.97a32.18 32.18 0 0 0 22.656 22.657c19.866 5.418 99.822 5.418 99.822 5.418s79.955 0 99.82-5.418a32.18 32.18 0 0 0 22.657-22.657c6.338-35.348 8.291-89.1-.164-123.134" />
<path fill="#fff" d="m102.421 128.06l66.328-38.418l-66.328-38.418z" />
</svg>
<!-- Placeholder for the image -->
<img v-if="!showIframe" :src="'https://img.youtube.com/vi/' + extractYouTubeID(sanitizedLink) + '/maxresdefault.jpg'"
class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 object-cover w-full h-full" />
<!-- The iframe will take up the full space when displayed -->
<iframe v-if="showIframe" :src="YOUTUBE_LINK + '?autoplay=1&mute=1'" title="YouTube video player"
frameborder="0" allowfullscreen autoplay loading="lazy"
class="absolute top-0 left-0 w-full h-full"></iframe>
</div>
</div>
</template>
<script setup lang="ts">
const showIframe = ref(false)
function extractYouTubeID(url: string) {
const regExp = /^.*(youtu.be\/|v\/|e\/|u\/\w+\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
const match = url.match(regExp);
if (match && match[2].length === 11) {
return match[2];
} else {
return null;
}
}
</script>
In the code above:
I use extractYoutubeID to extract a video ID from a provided link
Then I find a video thumbnail by using the video ID
as explained here on StackOverflow, I just used the one that gave the best impression, but you can use lower resolution thumbnail as well
I format it so it has the same size as the actual YT video.
I also added an SVG YT icon
Once the user hovers (desktop) over or clicks (mobile) the actual video is showed
This way your videos won't load on initial page load and thus speed it up. It should also positively affect your Page Insights
If you have any comments or questions, please let me know.
Cheers!
Bart