Next.js App Router در پروداکشن: از ایده تا سیستم پایدار
App Router فقط یک تغییر مسیر نیست؛ بازطراحی نحوه رندر، کش و مرزبندی مسئولیت در محصول است. در این مقاله مسیر عملیاتی که در پروژههای واقعی پارادایس کد طی میکنیم را مرور میکنیم.
علی مرتضوی
بنیانگذار پارادایس کد
چرا App Router دیگر یک انتخاب آزمایشی نیست
وقتی تیمهای محصول از Pages Router به App Router مهاجرت میکنند، اغلب تصور میکنند فقط ساختار پوشهها عوض شده است. در عمل، App Router مدل ذهنی جدیدی برای رندر، کش و مرزبندی مسئولیتها معرفی میکند. Server Components به شما اجازه میدهند بخش زیادی از منطق داده را نزدیک به سرور نگه دارید و JavaScript کمتری به مرورگر بفرستید؛ این یعنی زمان تعاملی اولیه بهتر و هزینه نگهداری پایینتر در بلندمدت.
در پروژههایی که با آنها کار کردهایم — از پلتفرمهای مطالعه دادهمحور تا فروشگاههای تخصصی — App Router زمانی ارزش واقعی میدهد که تیم قبل از کدنویسی، نقشه مسیرها، layoutها و مرز Client/Server را مشخص کرده باشد. بدون این نقشه، پروژه به سرعت به ترکیبی از use client پراکنده، waterfall درخواست و رفتارهای غیرقابل پیشبینی کش تبدیل میشود.
نکته مهم این است که App Router جایگزین معماری نیست؛ ابزار معماری است. اگر دامنه محصول پیچیده است، همچنان به لایه سرویس، قرارداد API و استراتژی state نیاز دارید. App Router فقط به شما کمک میکند این لایهها را در جای درست قرار دهید: رندر اولیه در سرور، تعامل در کلاینت، و کش در لایهای که Next.js مدیریت میکند.
در پروژههای production، یک سند کوتاه «قرارداد رندر» برای تیم بنویسید: کدام layoutها Server هستند، کدام routeها dynamic اجباری دارند، و چه زمانی revalidate مجاز است. این سند جلوی بحثهای تکراری در review را میگیرد و onboarding نفر جدید را سریعتر میکند.
طراحی ساختار route و layout قبل از اولین کامپوننت
اولین تصمیم عملی در پروداکشن، طراحی درخت layout است. هر layout باید یک مرز مشخص داشته باشد: چه چیزی در همه صفحات مشترک است، چه چیزی فقط در بخش ادمین لازم است، و کجا باید loading و error boundary قرار بگیرد. در تجربه ما، layoutهای تودرتو بهتر از یک layout غولپیکر عمل میکنند؛ چون تغییر در یک بخش، کل اپلیکیشن را تحت تأثیر قرار نمیدهد.
برای محصولات RTL مثل وبسایتهای فارسی، root layout جای مناسبی برای تنظیم lang، dir و فونت است. اما مراقب باشید منطق سنگین یا وابستگی به window را اینجا نیاورید. root layout باید تا حد ممکن Server Component بماند تا زمان بارگذاری اولیه پایدار بماند.
مسیرهای داینامیک را با نامگذاری معنادار طراحی کنید. به جای مسیرهای مبهم، از slugهای خوانا استفاده کنید و قرارداد یکنواخت برای صفحات لیست، جزئیات و ویرایش داشته باشید. این قرارداد بعداً در SEO، آنالیتیکس و پنل ادمین هم به کار میآید.
Edge runtime و Node runtime را اشتباه قاطی نکنید. کتابخانههایی که به fs یا برخی APIهای Node وابستهاند در edge خطا میدهند. قبل از انتخاب runtime برای route handler، dependency graph را بررسی کنید.
Server Components در مقابل Client Components
اشتباه رایج این است که همه چیز را Client Component میکنند چون «راحتتر است». در پروداکشن، معیار تصمیم ساده است: اگر به event handler، state محلی، effect یا API مرورگر نیاز ندارید، Server Component بمانید. کامپوننتهای لیست محتوا، کارت مقاله، جدول فقطخواندنی و حتی بخشهایی از فرم که صرفاً نمایشی هستند، کاندیدای خوبی برای سرور هستند.
وقتی مجبورید Client Component بسازید، سطح آن را تا حد ممکن پایین نگه دارید. الگوی leaf client مؤثر است: درخت بزرگ Server Component و فقط برگهای تعاملی client. این کار bundle را کوچک نگه میدارد و رندر اولیه را سریعتر میکند.
برای دادههایی که بین چند کامپوننت کلاینت به اشتراک گذاشته میشود، Context را بیرویه به layout کلاینتی نبرید. ابتدا بررسی کنید آیا میتوان داده را در سرور resolve کرد و به صورت props پایین فرستاد. اگر نه، از state سرور (مثل React Query یا Zustand) با مرز مشخص استفاده کنید.
برای تیمهای چندمحصوله، یک boilerplate داخلی با layout، auth guard، error handling و الگوی fetch استاندارد بسازید. App Router بدون الگوی مشترک دوباره به آشوب ختم میشود.
Data Fetching و کش در دنیای واقعی
در App Router، fetch دیگر فقط یک درخواست HTTP ساده نیست؛ با سیستم کش Next.js گره خورده است. در پروداکشن باید بدانید هر صفحه چه چیزی را cache میکند، چه زمانی revalidate میشود و آیا stale بودن داده برای کسبوکار قابل قبول است یا نه. برای فروشگاه، قیمت و موجودی معمولاً باید تازه باشند؛ برای بلاگ، revalidate چند دقیقهای اغلب کافی است.
الگوی route handler برای عملیاتهایی که نباید در RSC مستقیم انجام شوند — مثل webhook، آپلود، یا invalidate دستی — بسیار کاربردی است. این handlerها مرز امن بین دنیای داخلی و خارجی محصول هستند و باید اعتبارسنجی، rate limit و لاگ داشته باشند.
برای دادههای حساس کاربر، هرگز به کش پیشفرض تکیه نکنید. session و پروفایل باید در لایه auth مشخص شوند و در RSC با guard خوانده شوند. اشتباه در این نقطه میتواند باعث نشت داده بین کاربران شود.
Streaming و Suspense برای صفحات با بخشهای کند بسیار مؤثرند. بخش بالای صفحه سریع برسد، جدول سنگین بعداً stream شود. کاربر احساس سرعت میکند حتی اگر کل داده آماده نباشد.
عملکرد، خطا و تجربه کاربری در پروداکشن
فایلهای loading.tsx و error.tsx فقط برای زیبایی نیستند؛ بخشی از قرارداد محصول با کاربر هستند. loading باید ساختار صفحه را حفظ کند تا CLS پایین بماند. error باید پیام قابل فهم به فارسی بدهد و مسیر بازگشت یا تلاش مجدد داشته باشد.
برای بهبود LCP، تصاویر را با next/image و سایزهای مشخص استفاده کنید. فونتها را با next/font لود کنید تا FOIT/FOUT کنترل شود. در پروژههای RTL، پیشبارگذاری وزنهای ضروری فونت فارسی تأثیر محسوسی روی تجربه اولیه دارد.
INP را جدی بگیرید: handlerهای سنگین در کلاینت، rerenderهای بیمورد و لیستهای بزرگ بدون virtualization مستقیم روی تعامل اثر میگذارند. App Router فرصت رندر سبکتر اولیه را میدهد، اما اگر لایه کلاینت شلوغ باشد، این مزیت از بین میرود.
تست e2e روی build production اجرا شود، نه فقط dev. رفتار کش و RSC در dev با prod فرق دارد. Playwright روی preview deployment Vercel ارزش زیادی دارد.
چکلیست استقرار و نگهداری تیم
قبل از ریلیز، این موارد را بررسی کنید: آیا همه routeهای حساس محافظت شدهاند؟ آیا metadata و open graph برای صفحات کلیدی کامل است؟ آیا build در CI بدون هشدار کش یا dynamic اجباری غیرمنتظره عبور میکند؟ آیا log خطا در production به ابزار مانیتورینگ وصل است؟
برای تیمهای چندنفره، قرارداد codestyle درباره use client، محل fetch و نامگذاری route ضروری است. بدون قرارداد، هر توسعهدهنده الگوی خودش را میآورد و هزینه review و باگ بالا میرود.
App Router در پروداکشن موفق است وقتی تیم آن را بخشی از معماری محصول بداند، نه فقط فریمورک جدید. در پارادایس کد، همین رویکرد را در پروژههای مقیاسپذیر به کار میگیریم: طراحی مرزها اول، بهینهسازی بعد، و مستندسازی کوتاه برای هر تصمیم غیربدیهی.
نگهداری App Router یعنی بهروز ماندن با release notes Next.js. هر upgrade کوچک را در staging با smoke test عبور دهید. breaking change در caching رفتار صفحات شما را بدون تغییر کد عوض میکند.
دانش و مقالات
نیاز به اجرای همین مفاهیم در محصولتان دارید؟
پارادایس کد از مشاوره تا پیادهسازی کامل کنار شماست.