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" />
}