spinny:~/writing $ vim nextjs-16-cache-components.md
1~2لسنوات عديدة، كان أحد الأسئلة الأكثر إزعاجًا في Next.js هو: "هل هذه الصفحة ثابتة أم ديناميكية؟". يبدو الأمر وكأنه سؤال بسيط، حتى تقوم بإضافة مكالمة إلى `cookies()`، أو `fetch` بخيارات مختلفة، أو عميل قاعدة بيانات، أو نظام إدارة المحتوى (CMS)، أو عربة تسوق، أو جزء من المحتوى المخصص.3~4يعد Next.js 16 مثيرًا للاهتمام لأنه يحاول جعل هذه المحادثة أقل غموضًا. إنه لا يزيل التعقيد، ولكنه يغير النموذج العقلي: تكون المسارات ديناميكية بشكل افتراضي، وتعلن ذاكرة التخزين المؤقت عن نفسها عند الحاجة، ويصبح `Suspense` الطريقة الطبيعية لتكوين أغلفة سريعة بأجزاء تظل جديدة.5~6الميزة التي يجب فهمها هي مكونات ذاكرة التخزين المؤقت. تعد Stable Turbopack وReact Compiler و`proxy.ts` وواجهات برمجة التطبيقات الجديدة للإبطال مهمة، ولكنها تدور حول نفس المشكلة: إنشاء تطبيقات سريعة دون الحاجة إلى تخمين ما قرره إطار العمل خلف الكواليس.7~8## لأن هذا الشيء مهم9~10في التطبيق الحقيقي، لا يكون لديك فقط "صفحات ثابتة" و"صفحات ديناميكية". لديك قطع مختلفة باحتياجات مختلفة.11~12قد تتغير ورقة المنتج عدة مرات في اليوم. قد يتغير السعر في كثير من الأحيان. يجب أن يكون التوفر مباشرًا تقريبًا. اسم المستخدم شخصي. يمكن دفق التعليقات. يمكن أن يكون الشريط الجانبي مستقرًا. العربة لا.13~14إذا تعاملت مع كل شيء كوحدة واحدة، فسوف ينتهي بك الأمر دائمًا إلى أحد النقيضين:15~16- التخزين المؤقت العدواني وخطر رؤية البيانات القديمة؛17- العرض الديناميكي في كل مكان والأداء أسوأ من اللازم.18~19تعمل مكونات ذاكرة التخزين المؤقت على وجه التحديد على تجنب هذا الاختيار الخاطئ.20~21## النموذج على أرض الواقع22~23باستخدام `cacheComponents: true`، يمكنك الإعلان عن ما هو قابل للتخزين المؤقت باستخدام `"use cache"`. وبعد ذلك يمكنك ربط المدة والعلامات بـ `cacheLife()` و`cacheTag()`. تظل الأجزاء الديناميكية ديناميكية ويمكن عزلها باستخدام `Suspense`.24~25```mermaid26flowchart TD27 Request[طلب المستخدم] --> Shell[قذيفة مخبأة]28 Request --> Dynamic[أقسام ديناميكية]29 Shell --> FirstPaint[أول محتوى سريع]30 Dynamic --> Stream[الجري داخل التشويق]31 Stream --> Complete[صفحة كاملة]32```33~34الإعداد صغير:35~36```typescript37// next.config.ts38import type { NextConfig } from 'next';39~40const nextConfig: NextConfig = {41 cacheComponents: true,42};43~44export default nextConfig;45```46~47التغيير الكبير ليس في التكوين. إنها تتعلق بكيفية البدء في كتابة المكونات.48~49```tsx50// app/products/[slug]/page.tsx51import { Suspense } from 'react';52import { cacheLife, cacheTag } from 'next/cache';53~54async function getProduct(slug: string) {55 'use cache';56~57 cacheLife('hours');58 cacheTag(`product:${slug}`);59~60 return db.product.findUnique({ where: { slug } });61}62~63async function ProductDetails({ slug }: { slug: string }) {64 const product = await getProduct(slug);65~66 return (67 <section>68 <h1>{product.name}</h1>69 <p>{product.description}</p>70 </section>71 );72}73~74async function LiveInventory({ slug }: { slug: string }) {75 const inventory = await db.inventory.findFirst({ where: { slug } });76 return <p>{inventory.quantity} pezzi disponibili</p>;77}78~79export default async function ProductPage({ params }: { params: Promise<{ slug: string }> }) {80 const { slug } = await params;81~82 return (83 <>84 <ProductDetails slug={slug} />85 <Suspense fallback={<p>Controllo disponibilità...</p>}>86 <LiveInventory slug={slug} />87 </Suspense>88 </>89 );90}91```92~93ليس من الضروري أن تكون الصفحة مخزنة مؤقتًا بالكامل أو ديناميكية بالكامل. يمكن أن تكون ورقة المنتج سريعة وقابلة لإعادة الاستخدام. يمكن أن يبقى المخزون جديدًا. يرى المستخدم شيئًا على الفور، دون انتظار الجزء الأبطأ.94~95## `use cache` هو مستند قابل للتنفيذ96~97الشيء الذي يعجبني في `"use cache"` هو أنه يجبرك على توضيح نيتك. عندما تقرأ وظيفة ما، ستدرك على الفور أن شخصًا ما قد قرر: "يمكن إعادة استخدام هذه البيانات".98~99إنه مفيد بشكل خاص عندما لا تستخدم `fetch`. تقرأ العديد من التطبيقات البيانات من Prisma أو Drizzle أو مجموعات SDK الداخلية أو عملاء CMS أو وظائف الخدمة. في تلك الحالات، لم يكن المنطق القديم المبني على خيارات `fetch` كافيًا.100~101قاعدة أساسية:102~103- محتوى ذاكرة التخزين المؤقت مستقر نسبيًا؛104- استخدام العلامات الحبيبية؛105- يترك الأذونات الديناميكية والجلسات وعربات التسوق والإشعارات وحالات المعاملات؛106- ضع الأجزاء البطيئة بالداخل `Suspense`;107- قم بالقياس قبل أن تقول "لقد قمنا بتحسين الأداء".108~109## إبطال دون رمي كل شيء بعيدا110~111تكون ذاكرة التخزين المؤقت مفيدة فقط إذا كان بإمكانك تحديثها بدقة. هنا تصبح `cacheTag` و`revalidateTag` و`updateTag` مهمة.112~113مثال:114~115```typescript116'use server';117~118import { updateTag } from 'next/cache';119~120export async function updateProductName(productId: string, name: string) {121 await db.product.update({122 where: { id: productId },123 data: { name },124 });125~126 updateTag(`product:${productId}`);127}128```129~130التفاصيل المهمة هي العلامة. `product:${productId}` يحدّد حدودًا دقيقة. `products` يحكي دلوًا ضخمًا. في البداية يكون الدلو الضخم مريحًا؛ بعد بضعة أشهر يصبح السبب وراء إبطال نصف التطبيق لتغيير العنوان.131~132## Turbopack المستقر: الجزء الذي تسمعه كل يوم133~134يقوم Next.js 16 بإحضار Turbopack إلى مركز التطوير والبناء. إنها ليست الميزة الأكثر شاعرية، ولكنها الميزة التي تشعر بها أثناء العمل: الخادم الذي يبدأ مبكرًا، والتحديث الأسرع، والبنيات التي لا تشعر وكأنها استراحة قسرية لتناول القهوة.135~136ومع ذلك، لن أقوم بترحيل قاعدة تعليمات برمجية مليئة بالمكونات الإضافية المخصصة وعيناي مغمضتان. أود أن أتحقق:137~138- البناء المحلي139- استيراد غير قياسي140- MDX، SVG وCSS؛141- ملحقات Webpack المتبقية؛142- صفحات حرجة؛143- الاختلافات في أوقات البناء.144~145بالنسبة للمشاريع الجديدة، سأبدأ من الافتراضي. بالنسبة للأشخاص الناضجين، سأقوم بهجرة محسوبة.146~147## رد الفعل المترجم: إزالة الضوضاء، وليس الفكر148~149React Compiler 1.0 مستقر ويدعمه Next.js 16 باستخدام `reactCompiler`. الوعد هو تقليل الكثير من الحفظ اليدوي: تقليل `memo`، وتقليل `useMemo`، وتقليل `useCallback` المستخدمة "للسلامة".150~151```typescript152// next.config.ts153import type { NextConfig } from 'next';154~155const nextConfig: NextConfig = {156 reactCompiler: true,157};158~159export default nextConfig;160```161~162لن أعامله مثل الغبار السحري. يساعد المترجم عندما يتبع الكود قواعد React بشكل جيد. إذا كانت المكونات لها آثار جانبية غريبة، أو طفرات مخفية، أو خطافات سيئة الاستخدام، فيجب إصلاح ذلك أولاً.163~164الطريقة الصحية لتجربتها:165~1661. تحديث `eslint-plugin-react-hooks`;1672. إصلاح الانتهاكات الفعلية؛1683. وتمكينه في منطقة خاضعة للرقابة؛1694. قياس بناء الوقت والسلوك.1705. قم بإزالة الحفظ اليدوي فقط عندما لا تكون هناك حاجة إليه.171~172الهدف ليس محو كل `useMemo`. الهدف هو التوقف عن كتابة الحفظ الوقائي لأننا نخاف من التقديم.173~174## `proxy.ts` وحدود الشبكة175~176يصبح `middleware.ts` القديم `proxy.ts`. إنه تغيير في الاسم، ولكنه منطقي: يقع هذا الملف عند حدود الطلب، وهو ليس برنامجًا وسيطًا عامًا تقليديًا على نمط الواجهة الخلفية.177~178```typescript179// proxy.ts180import { NextRequest, NextResponse } from 'next/server';181~182export default function proxy(request: NextRequest) {183 const isLoggedIn = Boolean(request.cookies.get('session'));184~185 if (!isLoggedIn && request.nextUrl.pathname.startsWith('/dashboard')) {186 return NextResponse.redirect(new URL('/login', request.url));187 }188~189 return NextResponse.next();190}191```192~193القاعدة هنا بسيطة: أبقِها صغيرة. إعادة التوجيه، توجيه المصادقة، الرؤوس، عمليات إعادة الكتابة الأساسية. إذا بدأت تشعر وكأنها واجهة خلفية ثانية، فمن المحتمل أنها تفعل الكثير.194~195## كيف سأهاجر حقا196~197لن أقوم بتشغيل جميع الميزات مرة واحدة. سأفعل هذا:198~1991. أقوم بتحديث Next وReact وReact DOM؛2002. أقوم بتشغيل الكود الرسمي؛2013. أقوم بإصلاح التغييرات المعطلة على `params`، `searchParams`، `cookies()`، `headers()` و`draftMode()`؛2024. أقوم بترحيل `middleware.ts` إلى `proxy.ts`؛2035. أتحقق من الإصدارات والصفحات المهمة؛2046. أقوم بتمكين مكونات ذاكرة التخزين المؤقت في قسم حيث تؤدي ذاكرة التخزين المؤقت حاليًا إلى حدوث احتكاك؛2057. أقوم بتحديد اصطلاحات العلامات والإبطال؛2068. أحاول استخدام React Compiler بشكل منفصل؛2079. مقارنة المقاييس قبل وبعد.208~209الترحيل الجيد ليس هو الذي يستخدم كافة الميزات الجديدة. وهذا ما يجعل سلوك التطبيق أكثر قابلية للقراءة.210~211## ما يتغير في طريقة التفكير212~213الشيء الأكثر فائدة في Next.js 16 هو أنه يجبرك على تسمية النوايا بشكل أفضل. الوظيفة ليست مجرد "الحصول على المنتج من قاعدة البيانات". إنها "احصل على المنتج، يمكنني تخزينه مؤقتًا لساعات، وأقوم بإبطاله باستخدام هذه العلامة". المكون ليس مجرد "عرض الصفحة". إنها "هذه هي القشرة السريعة، وهذه القطعة شخصية، وهذا يأتي عبر البث المباشر."214~215في البداية يبدو الأمر وكأنه المزيد من العمل. ثم يصبح شكلاً من أشكال الهدوء. لم تعد قرارات الأداء مخفية في مزيج من الافتراضات والاستدلال والذاكرة القبلية. إنهم في الكود.216~217## مصادر مفيدة218~219- [ملاحظات الإصدار Next.js 16](https://nextjs.org/blog/next-16)220- [مكونات ذاكرة التخزين المؤقت - مستندات Next.js](https://nextjs.org/docs/app/getting-started/cache-components)221- [استخدام ذاكرة التخزين المؤقت - مستندات Next.js](https://nextjs.org/docs/app/api-reference/directives/use-cache)222- [رد الفعل المترجم v1.0](https://react.dev/blog/2025/10/07/react-compiler-1)223~
NORMAL · nextjs-16-cache-components.md [readonly]223 lines · :q to close