Lighthouse Journey #2 — The YouTube Problem

6 回视听by Huynh

“When one iframe slows the whole story.”

From the beginning, YouTube has been a core part of WakaranEng.
Our main content lives there.
We talk, react, and learn through videos —
so embedding YouTube into our site wasn’t optional.

But during our first Lighthouse audit,
one thing became painfully clear:

The YouTube iframe was the heaviest thing on the page.

Not our images.
Not our CSS.
Not our React components.
Just a single embed — and all the scripts it brought with it.


📉 What Lighthouse Told Us

Lighthouse didn’t blame our code directly.
Instead, it kept repeating the same warning:

“Reduce the impact of third-party code.”

When we looked deeper, almost all of that “third-party code”
came from the default YouTube embed:

  • The video player JavaScript
  • Tracking and analytics scripts
  • Extra CSS and assets
  • Multiple network calls to Google domains

And all of this loaded before the user even clicked “Play.”

Our site looked simple.
But under the hood, the browser was doing a lot of unnecessary work.

We needed a way to keep YouTube —
without letting it dominate the performance budget.


🧪 The Idea: Click First, Load Later

The solution we chose was simple in concept:

  1. Show a thumbnail instead of the full YouTube iframe.
  2. Only load the actual player when the user clicks “Play.”
  3. Use youtube-nocookie.com to reduce tracking and third-party cookies.

In other words:

“Don’t pay the cost of YouTube until the user actually wants YouTube.”

That led to the component we use now across WakaranEng.


⚙️ The Component We Built

Here is the exact component we use in production today:

'use client'

import { useState } from 'react'
import Image from 'next/image'

interface YouTubeEmbedProps {
  videoId: string
  title?: string
  thumbnail?: string
  className?: string
}

/**
 * Privacy-focused YouTube embed component
 * - Uses youtube-nocookie.com to minimize tracking
 * - Lazy loads iframe only when user clicks play
 * - Reduces third-party cookies and improves Lighthouse scores
 */
export default function YouTubeEmbed({
  videoId,
  title = 'YouTube video player',
  thumbnail,
  className = '',
}: YouTubeEmbedProps) {
  const [isIframeLoaded, setIsIframeLoaded] = useState(false)

  // Generate thumbnail URL if not provided
  const thumbnailUrl =
    thumbnail || `https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg`

  const handlePlayClick = () => {
    setIsIframeLoaded(true)
  }

  return (
    <div className={`relative aspect-video w-full ${className}`}>
      {!isIframeLoaded ? (
        <>
          {/* Thumbnail */}
          <Image
            src={thumbnailUrl}
            alt={title}
            fill
            className="object-cover object-center"
            priority
          />

          {/* Play Button Overlay */}
          <button
            onClick={handlePlayClick}
            className="absolute inset-0 flex items-center justify-center transition-opacity hover:opacity-90"
            aria-label="Play video"
          >
            <Image
              src="/images/playButton.png"
              alt="Play button"
              width={82}
              height={58}
              className="drop-shadow-playBtn max-md:h-[44px] max-md:w-[62px]"
            />
          </button>
        </>
      ) : (
        <iframe
          width="560"
          height="315"
          src={`https://www.youtube-nocookie.com/embed/${videoId}?autoplay=1&rel=0&modestbranding=1`}
          title={title}
          frameBorder="0"
          allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
          referrerPolicy="strict-origin-when-cross-origin"
          allowFullScreen
          className="absolute inset-0 h-full w-full"
        />
      )}
    </div>
  )
}

What this component actually does

  • Step 1 – Show only a thumbnail at first
    • Uses YouTube’s thumbnail (i.ytimg.com) or a custom one.
    • The page only loads a simple image, not the full player.
  • Step 2 – Overlay a custom Play button
    • Visual behavior feels like YouTube.
    • But technically, nothing heavy has loaded yet.
  • Step 3 – On click, load the real iframe
    • setIsIframeLoaded(true) swaps the thumbnail for the real player.
    • The iframe uses youtube-nocookie.com to reduce tracking.
    • Autoplay turns on only after the user explicitly clicks.

Result:
The browser doesn’t pay the “YouTube tax”
until the user actually wants to watch the video.


📈 The Impact on Lighthouse

After replacing all direct iframes with this component:

  • Initial page load became much lighter.
  • Third-party script impact dropped significantly.
  • Performance score jumped to green (100).
  • First Contentful Paint and Largest Contentful Paint improved.
  • The site felt faster — especially on slower networks.

The best part?

The user experience stayed the same.
People still see a video preview.
They still click a big Play button.
Only the implementation changed — not the intention.

“We didn’t remove YouTube.
We just stopped letting it load before it was invited.”


🎧 Why This Fits the WakaranEng Philosophy

WakaranEng is about clarity and respect:

  • Respect for the reader’s time.
  • Respect for their device and connection.
  • Respect for privacy wherever we can improve it.

This component is a small piece of that philosophy in code form:
less hidden work, more intentional behavior.

Optimizing Lighthouse wasn’t just about chasing numbers.
It was about aligning the technical reality of the site
with the values we say we care about.


🔜 Next in the Series

In the next part of this Lighthouse Journey,
we shift from performance to semantics:

Lighthouse Journey #3 – Small Fix, Big Impact: The Lang Tag Mistake

How a tiny change from en to en-US
fixed warning after warning in our audits.

And later:

Lighthouse Journey #4 – Writing for AI Search Engines

What it means to write a website
that both humans and AI can truly understand.


🌱 Reflection

This whole “YouTube problem” taught us something simple:

Not everything has to load right now.
Not everything deserves to be first in line.

Like learning English,
good performance is about timing, context, and intention.

“Optimizing a page is just another way of learning how to be clear.”

推荐博客