Next.js 15 फुलस्टैक (App Router + Server Actions) · पाठ

server-only और client-only से Module Boundaries

Poison-pill packages का उपयोग करके server secrets और भारी code को client bundles में जाने से रोकें।

पाठ 3, कुल 4 में से13 चरण

server-only और client-only से Module Boundaries, CoddyKit पर Next.js 15 फुलस्टैक (App Router + Server Actions) का एक निःशुल्क पाठ है। यह 4 में से 3वाँ पाठ है। इस अध्ययन पथ के 3 तक कोई भी पाठ पूरा पढ़ना निःशुल्क है — इसके बाद CoddyKit PRO हर पाठ अनलॉक करता है, साथ ही अंतर्निर्मित कोड संपादक और चौबीसों घंटे एआई शिक्षक के साथ व्यावहारिक अभ्यास भी उपलब्ध कराता है। यह Next.js 15 फुलस्टैक (App Router + Server Actions) सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। Next.js 15 फुलस्टैक (App Router + Server Actions) पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

मॉड्यूल सीमाएँ क्यों महत्वपूर्ण हैं

Next.js 15 JavaScript को दो अलग-अलग वातावरणों में चलाता है: Node.js सर्वर और ब्राउज़र क्लाइंट। app/ में लिखा गया कोड, उसके इंपोर्ट किए जाने के तरीके के आधार पर, चुपचाप किसी भी बंडल में पहुँच सकता है।

स्पष्ट सीमाओं के बिना, एक असावधान इंपोर्ट श्रृंखला इन चीज़ों को उजागर कर सकती है:

  • पर्यावरण चर में संग्रहित डेटाबेस क्रेडेंशियल और API कुंजियाँ
  • सर्वर-विशिष्ट व्यावसायिक तर्क, जिसे कभी भी उपयोगकर्ताओं तक नहीं पहुँचना चाहिए
  • भारी Node.js लाइब्रेरी (crypto, fs, net), जो क्लाइंट बंडल को बड़ा कर देती हैं

poison-pill पैकेज server-only और client-only Next.js का प्रचलित समाधान हैं। जैसे ही कोई मॉड्यूल गलत सीमा पार करता है, वे बिल्ड-समय त्रुटि उत्पन्न करते हैं — इससे कोड के प्रोडक्शन में भेजे जाने से पहले ही गलती पकड़ में आ जाती है।

पैकेज इंस्टॉल करना

दोनों पैकेज Next.js टीम द्वारा प्रकाशित किए जाते हैं और इनमें रनटाइम कोड नहीं होता। उनका पूरा उद्देश्य एक ऐसे sentinel इंपोर्ट की तरह काम करना है, जिसे बंडलर पहचान सके।

उन्हें अपने प्रोजेक्ट में एक बार इंस्टॉल करें:

npm install server-only client-only

ये बहुत छोटे हैं — हर पैकेज में केवल एक index.js होता है, जो गलत वातावरण में मूल्यांकित होने पर त्रुटि उत्पन्न करता है। बिल्ड पाइपलाइन (React की बंडलर स्थितियों के माध्यम से) यह सुनिश्चित करती है कि त्रुटि रनटाइम पर नहीं, बल्कि कंपाइल समय पर उत्पन्न हो।

आपको next.config.ts में कुछ भी कॉन्फ़िगर करने की आवश्यकता नहीं है। ये पैकेज उस react-server एक्सपोर्ट स्थिति पर निर्भर करते हैं, जिसे Next.js अपने-आप सेट करता है।

मॉड्यूल को केवल-सर्वर के रूप में चिह्नित करना

सर्वर-साइड सीक्रेट पढ़ने वाली, डेटाबेस से संपर्क करने वाली या Node.js के अंतर्निहित मॉड्यूल का उपयोग करने वाली हर फ़ाइल की शुरुआत एक इंपोर्ट से होनी चाहिए:

import 'server-only'

यदि कोई Client Component (या क्लाइंट-साइड का कोई कोड) कभी इस मॉड्यूल को इंपोर्ट करता है, तो Next.js उस इंपोर्ट की ओर संकेत करने वाले स्पष्ट त्रुटि संदेश के साथ बिल्ड रोक देगा। नीचे दिया गया उदाहरण एक डेटा-एक्सेस परत दिखाता है, जिसे कभी भी ब्राउज़र तक नहीं पहुँचना चाहिए।

// lib/db.ts
import 'server-only'
import { Pool } from 'pg'

const pool = new Pool({
  connectionString: process.env.DATABASE_URL, // secret — server only
})

export async function getUserById(id: string) {
  const { rows } = await pool.query(
    'SELECT id, name, email FROM users WHERE id = $1',
    [id]
  )
  return rows[0] ?? null
}

सीमा का उल्लंघन होने पर क्या होता है

मान लीजिए कि कोई डेवलपर गलती से केवल-सर्वर डेटा-एक्सेस परत को किसी Client Component में इंपोर्ट कर देता है। poison pill के बिना, गुप्त DATABASE_URL चुपचाप ब्राउज़र बंडल में दिखाई देने लगता।

server-only मौजूद होने पर Next.js तुरंत बिल्ड रोक देता है और यह प्रिंट करता है:

Error: This module cannot be imported from a Client Component module.
It should only be used from a Server Component.

इससे उल्लंघन को गलती से भेजना असंभव हो जाता है। त्रुटि नियतात्मक है — सीमा पार करने वाले हर next build और next dev हॉट-रीलोड पर यह उत्पन्न होती है।

// app/dashboard/page.tsx — Server Component, safe to import lib/db
import { getUserById } from '@/lib/db'

export default async function DashboardPage() {
  const user = await getUserById('user_123')
  return <h1>Welcome, {user?.name}</h1>
}

// app/components/ProfileCard.tsx — Client Component
'use client'
// import { getUserById } from '@/lib/db'  // ← BUILD ERROR if uncommented
export function ProfileCard({ name }: { name: string }) {
  return <p>{name}</p>
}

मॉड्यूल को केवल-क्लाइंट के रूप में चिह्नित करना

client-only इसका उलटा समस्या हल करता है। कुछ मॉड्यूल ब्राउज़र-विशेष API, जैसे window, document, localStorage या ब्राउज़र-विशिष्ट तृतीय-पक्ष SDK पर निर्भर करते हैं।

यदि ऐसे मॉड्यूल को Server Component में इंपोर्ट किया जाता है, तो Node.js रनटाइम पर त्रुटि उत्पन्न करेगा, क्योंकि सर्वर पर वे ब्राउज़र ग्लोबल मौजूद नहीं होते। client-only उस रनटाइम आश्चर्य को बिल्ड-समय त्रुटि में बदल देता है।

किसी भी ब्राउज़र-विशेष यूटिलिटी के शीर्ष पर यह इंपोर्ट जोड़ें:

import 'client-only'

// lib/analytics.ts
import 'client-only'

// This module calls browser APIs — it must never run on the server
export function trackEvent(name: string, props?: Record<string, unknown>) {
  if (typeof window === 'undefined') return // extra guard, but poison-pill fires first
  window.gtag?.('event', name, props)
}

export function getStoredUserId(): string | null {
  return localStorage.getItem('userId')
}

सुरक्षित पैटर्न: सर्वर डेटा को प्रॉप्स के रूप में भेजना

Next.js 15 का मानक पैटर्न है कि server-only मॉड्यूल का उपयोग करके Server Component में डेटा प्राप्त करें, फिर सुरक्षित, सीरियलाइज़ किए जा सकने वाले मानों को प्रॉप्स के रूप में Client Components में भेजें।

कोई सीक्रेट, डेटाबेस हैंडल या केवल Node.js में उपलब्ध ऑब्जेक्ट नेटवर्क सीमा पार नहीं करता — केवल ऐसा सादा डेटा जाता है, जिसे JSON में सुरक्षित रूप से सीरियलाइज़ किया जा सकता है।

// lib/user-service.ts
import 'server-only'
import { pool } from './db'

export interface UserProfile {
  id: string
  name: string
  avatarUrl: string
}

export async function getProfile(userId: string): Promise<UserProfile | null> {
  const { rows } = await pool.query(
    'SELECT id, name, avatar_url FROM users WHERE id = $1',
    [userId]
  )
  if (!rows[0]) return null
  return { id: rows[0].id, name: rows[0].name, avatarUrl: rows[0].avatar_url }
}

// app/profile/page.tsx — Server Component
import { getProfile } from '@/lib/user-service'
import { AvatarCard } from '@/components/AvatarCard' // 'use client'

export default async function ProfilePage({ params }: { params: { id: string } }) {
  const profile = await getProfile(params.id)
  if (!profile) return <p>Not found</p>
  // Only serialisable data crosses to the client
  return <AvatarCard name={profile.name} avatarUrl={profile.avatarUrl} />
}

Server Actions कोई बायपास नहीं हैं

Server Actions ऐसे फ़ंक्शन होते हैं जो सर्वर पर चलते हैं, लेकिन उन्हें क्लाइंट-साइड कोड से बुलाया जाता है। एक आम गलतफ़हमी यह है कि किसी फ़ंक्शन को 'use server' से चिह्नित करने पर पूरा मॉड्यूल अपने-आप सुरक्षित हो जाता है।

ऐसा नहीं है। 'use server' निर्देश केवल Next.js को उस फ़ंक्शन को HTTP एंडपॉइंट के रूप में उजागर करने के लिए कहता है। उसी फ़ाइल के अन्य एक्सपोर्ट सीधे इंपोर्ट किए जाने पर लीक हो सकते हैं।

सर्वोत्तम अभ्यास: Server Actions को समर्पित actions/ फ़ाइलों में रखें और साझा सर्वर यूटिलिटी को फिर भी server-only से सुरक्षित करें।

// app/actions/update-profile.ts
'use server'
import { getUserById } from '@/lib/db' // lib/db has 'server-only' — safe
import { revalidatePath } from 'next/cache'

export async function updateProfileAction(formData: FormData) {
  const name = formData.get('name') as string
  const userId = formData.get('userId') as string

  // Business logic runs entirely on the server
  const existing = await getUserById(userId)
  if (!existing) throw new Error('User not found')

  // db update omitted for brevity
  revalidatePath('/profile')
}

// app/profile/edit/page.tsx — this is a Client Component form
'use client'
import { updateProfileAction } from '@/app/actions/update-profile'

export function EditForm({ userId }: { userId: string }) {
  return (
    <form action={updateProfileAction}>
      <input type="hidden" name="userId" value={userId} />
      <input name="name" placeholder="New name" />
      <button type="submit">Save</button>
    </form>
  )
}

अपनी lib/ फ़ोल्डर को सीमा के अनुसार व्यवस्थित करना

एक अनुमानित फ़ोल्डर परंपरा से यह अनुमान लगाने की आवश्यकता नहीं रहती कि कोई यूटिलिटी किस वातावरण के लिए है। व्यापक रूप से अपनाया गया लेआउट इस प्रकार दिखता है:

  • lib/server/ — हर फ़ाइल की शुरुआत import 'server-only' से होती है
  • lib/client/ — हर फ़ाइल की शुरुआत import 'client-only' से होती है
  • lib/shared/ — पर्यावरण-विशिष्ट इंपोर्ट के बिना शुद्ध फ़ंक्शन (दोनों में सुरक्षित)

इस संरचना के साथ, कोड समीक्षक किसी नई यूटिलिटी की सामग्री पढ़ने से पहले ही बता सकता है कि उसे सही जगह रखा गया है या नहीं। CI लिंटिंग नियम यह भी सुनिश्चित कर सकते हैं कि lib/server/ के अंदर की फ़ाइलों में sentinel इंपोर्ट मौजूद हो।

// lib/shared/format.ts — no sentinel needed, works anywhere
export function formatCurrency(amount: number, currency = 'USD'): string {
  return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount)
}

// lib/server/stripe.ts
import 'server-only'
import Stripe from 'stripe'

export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2024-11-20.acacia',
})

// lib/client/toast.ts
import 'client-only'
import { toast } from 'sonner'

export function showSuccess(msg: string) {
  toast.success(msg)
}

TypeScript पथ उपनामों के साथ संयोजन करना

tsconfig.json में TypeScript पथ उपनाम पूरे कोडबेस में सीमा-जागरूक इंपोर्ट को सुविधाजनक और सुसंगत बनाते हैं। आप सीमा को सीधे उपनाम के नाम में दर्शा सकते हैं, जिससे इंपोर्ट स्वयं अपना उद्देश्य स्पष्ट करते हैं।

// tsconfig.json (relevant excerpt)
// {
//   "compilerOptions": {
//     "paths": {
//       "@server/*": ["./lib/server/*"],
//       "@client/*": ["./lib/client/*"],
//       "@shared/*": ["./lib/shared/*"]
//     }
//   }
// }

// Usage in a Server Component:
import { stripe } from '@server/stripe'
import { formatCurrency } from '@shared/format'

// Usage in a Client Component:
import { showSuccess } from '@client/toast'
import { formatCurrency } from '@shared/format'

// Attempting to import @server/* in a Client Component
// triggers the server-only build error immediately.

निर्देशों के बिना तृतीय-पक्ष पैकेज

कई npm पैकेज (विशेषकर पुराने पैकेज) में 'use client' या 'use server' निर्देश नहीं होते। Next.js बंडलर एक अनुमान-आधारित नियम लागू करता है: यदि किसी पैकेज में कोई निर्देश नहीं है, तो उसे साझा माना जाता है — यानी वह दोनों वातावरणों के लिए योग्य है।

जब कोई पैकेज आंतरिक रूप से ब्राउज़र ग्लोबल का उपयोग करता है, तब यह समस्या बन सकता है। इसका समाधान यह है कि उसे अपने lib/client/ मॉड्यूल में लपेटें और उसमें client-only चिह्नित करें, ताकि इंपोर्ट श्रृंखला स्पष्ट और जाँची जा सके।

// lib/client/chart-wrapper.ts
import 'client-only'
// chart.js has no 'use client' directive but uses window internally
import { Chart, registerables } from 'chart.js'

Chart.register(...registerables)

export { Chart }
export type { ChartConfiguration } from 'chart.js'

// components/RevenueChart.tsx
'use client'
import { Chart } from '@client/chart-wrapper' // boundary enforced
import { useEffect, useRef } from 'react'

export function RevenueChart({ data }: { data: number[] }) {
  const ref = useRef<HTMLCanvasElement>(null)
  useEffect(() => {
    if (!ref.current) return
    const ctx = ref.current.getContext('2d')!
    new Chart(ctx, { type: 'line', data: { labels: data.map(String), datasets: [{ data }] } })
  }, [data])
  return <canvas ref={ref} />
}

@next/bundle-analyzer से अपने बंडल सत्यापित करना

poison-pill पैकेज बिल्ड समय पर आकस्मिक लीक को रोकते हैं, लेकिन अपने बंडल को दृश्य रूप से सत्यापित करना फिर भी उपयोगी है। @next/bundle-analyzer पैकेज हर बंडल के प्रत्येक मॉड्यूल का इंटरैक्टिव ट्रीममैप बनाता है।

इसका उपयोग यह सुनिश्चित करने के लिए करें कि केवल-सर्वर मॉड्यूल (डेटाबेस क्लाइंट, Stripe SDK, भारी Node.js लाइब्रेरी) क्लाइंट चंक में मौजूद न हों और इसका उलटा भी सही हो। यदि sentinel इंपोर्ट के बावजूद सीक्रेट वाला मॉड्यूल क्लाइंट बंडल में दिखाई देता है, तो आम तौर पर इसका अर्थ होता है कि किसी डायनेमिक इंपोर्ट या री-एक्सपोर्ट ने जाँच को दरकिनार कर दिया।

// next.config.ts
import type { NextConfig } from 'next'
import withBundleAnalyzer from '@next/bundle-analyzer'

const withAnalyzer = withBundleAnalyzer({
  enabled: process.env.ANALYZE === 'true',
})

const nextConfig: NextConfig = {
  // your existing config
}

export default withAnalyzer(nextConfig)

// Run analysis:
// ANALYZE=true next build
// Opens two browser tabs:
//   - client.html  (browser bundle — check for leaked server deps)
//   - server.html  (server bundle)

ज्ञान जाँच: server-only बनाम client-only

नीचे दिए गए प्रश्न का सबसे अच्छा उत्तर चुनें।

पुनरावलोकन: server-only और client-only के साथ मॉड्यूल सीमाएँ

इस पाठ में आपने सीखा कि Next.js 15 एप्लिकेशन में कठोर मॉड्यूल सीमाएँ कैसे लागू की जाती हैं:

  • import 'server-only' — किसी भी क्लाइंट-साइड कोड से इंपोर्ट किए जाने पर मॉड्यूल को बिल्ड-समय त्रुटि में बदल देता है। इसका उपयोग डेटाबेस क्लाइंट, सीक्रेट पढ़ने वाली यूटिलिटी और केवल Node.js वाले कोड पर करें।
  • import 'client-only' — ब्राउज़र-विशेष मॉड्यूल के लिए यही पैटर्न अपनाता है और सर्वर-साइड इंपोर्ट को रनटाइम क्रैश का कारण बनने से पहले पकड़ लेता है।
  • सुरक्षित डेटा-प्रवाह पैटर्न: server-only यूटिलिटी का उपयोग करके Server Component में डेटा प्राप्त करें, फिर सीरियलाइज़ किए जा सकने वाले प्रॉप्स Client Components को भेजें — कोई सीक्रेट या Node API नेटवर्क के पार न जाए।
  • lib/ को server/, client/ और shared/ उप-डायरेक्टरी में व्यवस्थित करें और सीमाओं को स्वयं स्पष्ट बनाने के लिए TypeScript पथ उपनामों के साथ उनका मेल रखें।
  • जिन तृतीय-पक्ष पैकेजों में निर्देश नहीं हैं, उन्हें अपनी सीमा-चिह्नित मॉड्यूल के अंदर लपेटें, ताकि इंपोर्ट ग्राफ़ की जाँच की जा सके।
  • क्लाइंट चंक में कोई केवल-सर्वर निर्भरता दिखाई न दे, यह दृश्य रूप से सत्यापित करने के लिए poison-pill पैकेजों को @next/bundle-analyzer के साथ मिलाकर उपयोग करें।

इन दोनों पैकेजों को जोड़ने में लगभग कोई लागत नहीं आती और वे सुरक्षा तथा प्रदर्शन संबंधी बग की एक पूरी श्रेणी को प्रोडक्शन तक पहुँचने से पहले ही समाप्त कर देते हैं।

शुरुआत निःशुल्क

एआई शिक्षक के साथ TypeScript सीखें — निःशुल्क

अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।

पाठ्यक्रम
22
पाठ
88

अक्सर पूछे जाने वाले प्रश्न

क्या “server-only और client-only से Module Boundaries” पाठ निःशुल्क है?

हाँ — Next.js 15 फुलस्टैक (App Router + Server Actions) अध्ययन पथ के 3 तक कोई भी पाठ, जिसमें “server-only और client-only से Module Boundaries” भी शामिल है, यहाँ वेब पर पूरा पढ़ना निःशुल्क है। इसके बाद CoddyKit PRO हर पाठ अनलॉक करता है, साथ ही अंतर्निर्मित कोड संपादक और चौबीसों घंटे एआई शिक्षक के साथ इंटरैक्टिव अभ्यास भी उपलब्ध कराता है। Next.js 15 फुलस्टैक (App Router + Server Actions) पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

“server-only और client-only से Module Boundaries” में मैं क्या सीखूँगा?

Poison-pill packages का उपयोग करके server secrets और भारी code को client bundles में जाने से रोकें। आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ Next.js 15 फुलस्टैक (App Router + Server Actions) का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।

क्या Next.js 15 फुलस्टैक (App Router + Server Actions) शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?

पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर Next.js 15 फुलस्टैक (App Router + Server Actions) शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 3वाँ पाठ है।

“server-only और client-only से Module Boundaries” पाठ पूरा करने में कितना समय लगता है?

CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।

क्या मैं इस Next.js 15 फुलस्टैक (App Router + Server Actions) पाठ में कोड लिख और चला सकता हूँ?

हाँ। हर Next.js 15 फुलस्टैक (App Router + Server Actions) पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।

इस पाठ्यक्रम के सभी पाठ

  1. Client Bundle का विश्लेषण और संकुचन
  2. Turbopack और Compiler Configuration का गहन अध्ययन
  3. server-only और client-only से Module Boundaries
  4. Dynamic Imports, Code Splitting और Lazy Hydration
← Next.js 15 फुलस्टैक (App Router + Server Actions) पर वापस जाएँ