𝗛𝗼𝘄 𝗪𝗲 𝗖𝘂𝘁 𝗦𝗹𝗼𝘄 𝗥𝗲𝘀𝗽𝗼𝗻𝘀𝗲𝘀 𝗯𝘆 𝟴𝟬%
Subito is a top marketplace in Italy. We handle thousands of requests every minute. Our ad detail page is vital for SEO and revenue.
We moved this page from Next.js Pages Router to App Router. We did not stop product work to do this. We moved in small steps.
Here is how we did it.
𝗧𝗵𝗲 𝗔𝗽𝗽𝗿𝗼𝗮𝗰𝗵
We used an incremental strategy. We added the App Router tree alongside the old Pages Router. This let us ship new features while we migrated.
We used Server Components to own data fetching. This removed the need to pass data through many layers. We also created a Data Access Layer. This made sure we only fetch data once per request.
We used Suspense and the use() hook to enable HTML streaming. This shows a skeleton screen while data loads. The user sees the page faster.
𝗧𝗵𝗲 𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲𝘀
Problem 1: HTTP 410 Gone Search engines need a 410 status when a page is permanently removed. The App Router does not have a built-in way to send this. We solved this using our Express server. The server intercepts the response and changes the status code.
Problem 2: HTML Streaming We found that our loading skeletons did not appear. The page stayed blank for seconds.
We discovered that Nginx and Akamai were buffering our responses. If the CDN buffers the HTML, streaming fails. We had to turn off buffering in Nginx and apply custom settings in Akamai. Once we fixed this, content streamed to the user perfectly.
𝗧𝗵𝗲 𝗥𝗼𝗹𝗹𝗼𝘂𝘁
We rolled out in two phases to protect our SEO.
Phase 1: We moved traffic to the App Router but kept streaming off. We did this one category at a time.
Phase 2: We enabled HTML streaming. We tested this on small categories first. Our SEO team monitored rankings for two weeks before we moved to the next category.
𝗧𝗵𝗲 𝗥𝗲𝘀𝘂𝗹𝘁𝘀
The results were huge. Before the migration, up to 40% of our responses were slow. After the migration, slow responses dropped by 80%.
Most pages now load in under 500ms.
𝗧𝗮𝗸𝗲𝗮𝘄𝗮𝘆𝘀
- Use parallel routing to migrate without stopping feature work.
- A custom server layer helps you control traffic and fix framework gaps.
- Streaming requires configuration at every layer. Check Nginx and your CDN.
- Test your SEO metrics during the rollout.
چگونه با مهاجرت به Next.js App Router، پاسخهای کند را تا ۸۰٪ کاهش دادیم
در این مقاله، ما تجربه خود را از مهاجرت از Pages Router به App Router در Next.js به اشتراک میگذاریم و بررسی میکنیم که چگونه این تغییر باعث بهبود چشمگیر عملکرد و کاهش ۸۰ درصدی پاسخهای کند (slow responses) شد.
مشکل: گلوگاههای عملکردی در Pages Router
در ساختار قدیمی ما (Pages Router)، بیشتر دادهها در سمت کلاینت واکشی میشدند. این موضوع منجر به چند مشکل اساسی میشد:
- اثر واترفال (Waterfall Effect): کامپوننتها باید ابتدا رندر میشدند، سپس به کلاینت میرسیدند و در نهایت درخواستهای API را ارسال میکردند. این یعنی لایههای مختلف اپلیکیشن به ترتیب و با تأخیر پشت سر هم بارگذاری میشدند.
- حجم بالای جاوااسکریپت: برای مدیریت وضعیت (state) و واکشی دادهها در سمت کلاینت، حجم زیادی از کدها به مرورگر فرستاده میشد.
- زمان بالا تا تعامل (TTI): کاربر باید منتظر میماند تا تمام کدهای جاوااسکریپت دانلود و اجرا شوند تا بتواند با صفحه تعامل داشته باشد.
راه حل: قدرت App Router و Server Components
با مهاجرت به App Router، ما توانستیم از قابلیتهای جدید Next.js برای بهینهسازی مسیرهای رندرینگ استفاده کنیم.
۱. استفاده از Server Components
بزرگترین تغییر، استفاده از React Server Components (RSC) بود. با این کار، ما توانستیم بخش زیادی از منطق واکشی دادهها را به سرور منتقل کنیم.
- کاهش حجم باندل: کدهای مربوط به واکشی دادهها و کتابخانههای سنگین دیگر به مرورگر کاربر فرستاده نمیشوند.
- واکشی داده در نزدیکی منبع: دادهها مستقیماً در سرور و در نزدیکی دیتابیس یا سرویسهای داخلی واکشی میشوند، که تأخیر شبکه را به شدت کاهش میدهد.
۲. بهینهسازی واکشی دادهها (Data Fetching)
در App Router، تابع fetch با قابلیتهای جدیدی تقویت شده است. ما توانستیم از استراتژیهای کشینگ (Caching) بهتری استفاده کنیم:
// مثال از واکشی داده با کشینگ در سرور
const res = await fetch('https://api.example.com/data', { next: { revalidate: 3600 } });
const data = await res.json();
این کار باعث میشود که درخواستهای تکراری به سمت API ارسال نشود و پاسخها بسیار سریعتر ارائه شوند.
۳. استریمینگ و Suspense
یکی از ویژگیهای جذاب، استفاده از Streaming بود. به جای اینکه کاربر منتظر بماند تا کل صفحه آماده شود، میتوانیم بخشهای مختلف را به صورت جداگانه ارسال کنیم. با استفاده از Suspense از React، میتوانیم برای بخشهای سنگین، حالتهای Loading نمایش دهیم:
<Suspense fallback={<LoadingSkeleton />}>
<SlowComponent />
</Suspense>
این کار باعث میشود که کاربر احساس کند اپلیکیشن بسیار سریعتر پاسخ میدهد، حتی اگر برخی بخشها هنوز در حال بارگذاری باشند.
چالشها و درسهای آموخته شده
مهاجرت آسان نبود. ما با چالشهایی مثل:
- تغییر در مدل مدیریت وضعیت (State Management).
- درک عمیقتر تفاوت بین Client و Server Components.
- بازنویسی برخی بخشهای پیچیده که به قابلیتهای کلاینت وابسته بودند.
مواجه شدیم. اما نتایج نهایی ارزش این تلاش را داشت.
نتیجهگیری
مهاجرت به Next.js App Router برای ما فراتر از یک تغییر تکنولوژی ساده بود؛ این یک تغییر پارادایم در نحوه تفکر ما درباره رندرینگ و انتقال داده بود. با کاهش ۸۰ درصدی پاسخهای کند، تجربه کاربری ما به طرز چشمگیری بهبود یافت.