Advanced

SSR / Next.js

How ytcn works with Server Components and server-side rendering.

Overview

All ytcn components are marked with "use client". This means they run exclusively in the browser. However, you can safely import them from Server Components — Next.js handles the client boundary automatically.

Safe import pattern

app/videos/[id]/page.tsx
// This is a Server Component (no "use client" directive)
import { YtcnPlayer } from "@/components/ytcn/ytcn-player"

export default async function VideoPage({
  params,
}: {
  params: Promise<{ id: string }>
}) {
  const { id } = await params

  // Server-side data fetching
  const video = await getVideoDetails(id)

  return (
    <main>
      <h1>{video.title}</h1>
      {/* YtcnPlayer is "use client" — Next.js handles the boundary */}
      <YtcnPlayer videoId={id} />
    </main>
  )
}

No window access at module level

ytcn components never access window, document, or navigator at module scope. All browser APIs are accessed inside useEffect or event handlers. This ensures zero SSR errors during the build phase.

Dynamic import (optional)

If you want to lazy-load the player to reduce the initial JavaScript bundle, use next/dynamic:

components/lazy-player.tsx
import dynamic from "next/dynamic"

const LazyPlayer = dynamic(
  () => import("@/components/ytcn/ytcn-player").then((m) => m.YtcnPlayer),
  {
    ssr: false,
    loading: () => (
      <div className="aspect-video bg-muted rounded-lg animate-pulse" />
    ),
  }
)

export function VideoSection({ videoId }: { videoId: string }) {
  return <LazyPlayer videoId={videoId} />
}

Pages Router

ytcn works with both the App Router and Pages Router. In the Pages Router, all pages are client components by default, so no special handling is needed. Just import and use directly.

pages/video.tsx
import { YtcnPlayer } from "@/components/ytcn/ytcn-player"

export default function VideoPage() {
  return <YtcnPlayer videoId="dQw4w9WgXcQ" />
}