السرعة ليست رفاهية تقنية، بل عامل حاسم في بقاء الزائر ورضاه وفي ترتيبك بمحرّكات البحث. تشير دراسات عديدة إلى أنّ كل ثانية تأخير إضافية ترفع نسبة المغادرة بشكل ملموس. الخبر الجيّد أنّ معظم بطء المواقع يأتي من أسباب قليلة معروفة، ومعالجتها لا تتطلّب خبرة عميقة. الجزء الأول من هذا المقال يعرض القائمة المرتّبة بالأهمّية، والجزء الثاني يعرض أرقاماً وقرارات فعلية من خطوة بناء تطبيق ويب عربي حقيقي — لأنّ الأرقام هي ما يحدّد أين تضع جهدك فعلاً.
1. الصور: السبب الأوّل للبطء
الصور تشكّل غالباً أكبر حجم في الصفحة. عالِجها على عدّة جبهات:
- الصيغة الحديثة: استخدم
WebPأوAVIFبدلJPG/PNG— توفّر 25–50% من الحجم بجودة مماثلة. - المقاس الصحيح: لا تعرض صورة بعرض 3000 بكسل في مساحة 400 بكسل. صدِّرها بالمقاس الفعلي.
- أبعاد ثابتة: حدِّد
widthوheightفي الوسم لتجنّب «قفز» التخطيط أثناء التحميل.
الأبعاد الصريحة ليست تفصيلاً تجميلياً: المتصفّح يحتاجها ليحسب نسبة العرض إلى الارتفاع قبل وصول أي بايت من الصورة، فيحجز المساحة ولا يدفع النصّ للأسفل عند اكتمال التحميل. غياب هذين الوسمين هو السبب الأول لتدهور مؤشّر ثبات التخطيط في المواقع العربية التي تعتمد صوراً كثيرة.
2. التحميل الكسول (Lazy Loading)
لا داعي لتحميل صورة في أسفل الصفحة قبل أن يصل إليها المستخدم. أضِف loading="lazy" للصور خارج الشاشة الأولى، واحتفظ بالصورة الأهمّ في الأعلى بـfetchpriority="high" لتظهر فوراً. النتيجة: تحميل أوّلي أخفّ وأسرع بكثير.
القاعدة العملية: كل صورة تحت حدّ الشاشة الأولى تأخذ loading="lazy"، وكل صورة داخل الشاشة الأولى تبقى بلا كَسَل. الخطأ المتكرّر هو تكسيل شعار الترويسة أو صورة الغلاف: فتتحوّل من موردٍ يُطلب مبكراً إلى موردٍ يُطلب بعد حساب التخطيط، فيتأخّر أكبر عنصر مرئي بدل أن يتقدّم. في صفحة هذا الموقع نفسها، شعار التذييل يحمل loading="lazy" وأبعاداً صريحة، بينما شعار الترويسة يُحمَّل عادياً بأبعاد ثابتة.
3. استثمر الكاش (Caching)
الملفّات التي لا تتغيّر كثيراً (الصور، الخطوط، ملفّات CSS/JS) يجب أن يحفظها المتصفّح محلياً ليُعيد استخدامها. اضبط ترويسات الكاش على الخادم: عمر طويل للأصول الثابتة المرقّمة، وno-cache لملفّات HTML حتى تصل التحديثات فوراً. زيارة ثانية للموقع يجب أن تكون شبه فورية.
main.css?v=20260809. هكذا تستفيد من الكاش الطويل، وعند التحديث تغيّر الرقم فيجلب المتصفّح النسخة الجديدة دون انتظار.
4. الخطوط: جمالٌ بثمن
خطوط الويب قد تؤخّر ظهور النص. خفِّف أثرها:
- استخدم
preconnectلمصدر الخطوط لتبدأ المصافحة مبكراً. - أضِف
font-display: swapليظهر النص بخطّ بديل فوراً ثم يُستبدل. - حمِّل الأوزان التي تستعملها فقط، لا العائلة كاملة.
5. قلّل الطلبات وحجم الكود
كل ملف خارجي = طلب شبكة إضافي. ادمج ما يمكن دمجه، واحذف مكتبات لا تستعمل منها سوى دالّة واحدة، وأجّل تحميل السكربتات غير الحرجة بـdefer أو async حتى لا تحجب عرض الصفحة. الكود الأقل دائماً أسرع.
6. افهم Core Web Vitals
هي ثلاثة مؤشّرات يقيس بها Google تجربة المستخدم الفعلية، وتؤثّر في ترتيبك:
- LCP (أكبر عنصر مرئي): يجب أن يظهر خلال 2.5 ثانية. حسِّنه بتسريع الصورة/العنوان الرئيسي.
- INP (سرعة الاستجابة للتفاعل): اجعل تفاعل الأزرار فورياً بتقليل عمل JavaScript الثقيل.
- CLS (ثبات التخطيط): امنع قفز العناصر بتحديد أبعاد الصور والإعلانات مسبقاً.
قِس موقعك مجاناً عبر أداة PageSpeed Insights من Google، وستحصل على قائمة محدّدة بما يجب إصلاحه.
7. فعّل الضغط على الخادم (Gzip / Brotli)
ملفّات النص (HTML, CSS, JS) قابلة للضغط بنسبة تصل إلى 70–80% قبل إرسالها للمتصفّح. معظم منصّات الاستضافة الحديثة تفعّل Brotli أو Gzip تلقائياً، لكن تأكّد من ذلك — فهو من أرخص المكاسب وأكبرها. يمكنك التحقّق من ترويسة الاستجابة content-encoding في تبويب الشبكة بأدوات المطوّر.
8. استعن بشبكة توصيل المحتوى (CDN)
الـCDN يوزّع نسخاً من ملفّاتك على خوادم قريبة جغرافياً من زوّارك، فيصل المحتوى من أقرب نقطة بدل قطع نصف الكرة الأرضية. النتيجة: زمن استجابة أقل لكل زائر مهما كان مكانه. كثير من خدمات الاستضافة (ومنها Firebase Hosting) تقدّم CDN مدمجاً دون إعداد إضافي.
9. روّض السكربتات الخارجية (Third-party)
أدوات التحليلات، الإعلانات، أزرار التواصل، والدردشة — كلّها سكربتات من جهات خارجية قد تبطّئ موقعك أكثر من كودك أنت. عالِجها بـ:
- تحميلها بـ
asyncأوdeferحتى لا تحجب عرض الصفحة. - تأجيل غير الحرج منها حتى تفاعل المستخدم أو ظهور العنصر.
- حذف ما لم تعد تستعمله فعلاً — كل سكربت له ثمن.
راقب «الميزانية» الإجمالية للصفحة؛ موقع سريع بكودك قد يتباطأ بسبب خمسة سكربتات خارجية. وإن أضفت شبكة إعلانات، فاعلم أنّ ضبطها يمسّ الأمان لا الأداء وحده — راجع سياسة أمان المحتوى مع أطراف ثالثة قبل أن تفتح نطاقات جديدة في موقعك.
ما فعلناه في مشروع حقيقي: جدول أحجام البناء الفعلي
كل ما سبق معروف. ما ليس معروفاً هو مقدار ما يعطيه كل بند فعلاً، والأرقام وحدها تحسم ذلك. في تطبيق ويب عربي لمتابعة الحمل، خطوة البناء تصغّر ملفّات JS وCSS عبر esbuild وتُخرجها إلى مجلّد public/dist/، مع بقاء ملفّات المصدر للتطوير، ثم تطبع جدول الأحجام قبل التصغير وبعده حتى يكون الأثر مرئياً في كل بناء لا مجرّد تخمين. هذه نتيجة تشغيل فعلية:
js/app.js — من 384KB إلى 253.5KB (أقلّ بـ34%)
js/admin.js — من 110.5KB إلى 72.2KB (أقلّ بـ35%)
js/i18n-content.js — من 79.1KB إلى 73.7KB (أقلّ بـ7% فقط)
js/i18n.js — من 36.9KB إلى 26.9KB (أقلّ بـ27%)
js/i18n-ui.js — من 27.2KB إلى 24.3KB (أقلّ بـ11%)
js/imageStore.js — من 21.5KB إلى 8.5KB (أقلّ بـ60%)
js/native-bridge.js — من 15.2KB إلى 4.7KB (أقلّ بـ69%)
js/content-protection.js — من 8.9KB إلى 2.2KB (أقلّ بـ75%)
js/datepicker.js — من 8.3KB إلى 4.7KB (أقلّ بـ43%)
css/main.css — من 95.9KB إلى 83.9KB (أقلّ بـ13%)
css/admin.css — من 21.9KB إلى 20.5KB (أقلّ بـ6%)
المجموع: 811.2KB تنزل إلى 575.6KB، أي توفير 235.6KB (نحو 29%) من سطر أمر واحد بلا أي تعديل على الكود. لكنّ المتوسّط يخفي الدرس الحقيقي: التفاوت بين 75% و7% هو المعلومة المفيدة، لا الرقم الإجمالي.
لماذا ينضغط ملف 75% وآخر 7% فقط؟
لأنّ التصغير (minification) يفعل ثلاثة أشياء فقط: يحذف المسافات والأسطر الفارغة، ويحذف التعليقات، ويقصّر أسماء المتغيّرات والدوالّ المحلّية إلى حرف أو حرفين. وهو لا يمسّ محتوى النصوص إطلاقاً — لا يستطيع، لأنّ النصّ داخل علامات التنصيص جزء من مخرجات البرنامج، وتغييره تغييرٌ للسلوك.
من هنا تُفهم الأرقام أعلاه:
- ملف كلّه منطق:
content-protection.jsمنطق خالص بأسماء متغيّرات وصفية وتعليقات عربية شارحة. المسافات والتعليقات والأسماء الطويلة تُلتهم كلّها، فينزل من 8.9KB إلى 2.2KB — أي إنّ 75% من الملف لم يكن كوداً يحتاجه المتصفّح أصلاً، بل تنسيقاً وشرحاً موجّهاً للبشر. - ملف كلّه جُمَل عربية:
i18n-content.jsقاموس نصوص للترجمة: جُمَل ومحتوى معروض. لا متغيّرات محلّية تُقصَّر ولا تعليقات تُحذف تُذكر — فلا يبقى للتصغير سوى المسافات بين المفاتيح. النتيجة 7% فقط، من 79.1KB إلى 73.7KB. - ملف مختلط:
app.jsمنطق ضخم لكنه يحمل أيضاً محتوى عربياً طويلاً. فجاء في المنتصف: 34%.
الاستنتاج المهمّ: نسبة الانضغاط مؤشّر على نوع الملف لا على جودة الأداة. إذا رأيت ملفاً لا ينضغط، فأنت لا تنظر إلى فشل في التصغير، بل إلى ملف بيانات تسلّل إلى طبقة الكود. وعلاج ملفّات البيانات مختلف تماماً.
app.js المصغَّر تقريباً — ويُحمَّل كلّها لكل زائرة، بينما الغالبية العظمى تقرأ بالعربية ولن تلمس القاموس الإنجليزي أبداً. لا تُحمّل قاموس لغة لا يقرأها المستخدم: افصل كل لغة في ملف، وحمّل ملف اللغة الثانية عند تبديل اللغة فقط عبر استيراد ديناميكي أو حقن وسم script عند الحاجة.
المبدأ يتعدّى الترجمة: قوائم المدن، رموز الدول، جداول المحتوى الطويلة، بيانات الأسئلة الشائعة — كلّها مرشّحة للنقل خارج حزمة الإقلاع. اسأل عن كل ملف: هل يحتاجه المستخدم في الثانية الأولى، أم عند فعلٍ محدّد؟ ما يُحتاج عند فعل محدّد يُحمَّل عند ذلك الفعل. للتفصيل في ضبط أداة التصغير مع المحتوى العربي، انظر تصغير كود عربي بـesbuild.
الخطأ الذي كلّفنا أكثر من 50 كيلوبايت: الترميز
أدوات التصغير الحديثة تُخرج الحروف غير اللاتينية بصيغة هروب سادس عشري افتراضاً، ضماناً لسلامة الملف مهما كان ترميز الخادم. عملياً: كل حرف عربي واحد يتحوّل إلى سلسلة من ستّة محارف لاتينية. في ملف يحمل آلاف الجُمَل العربية، النتيجة عكس المقصود تماماً — خرج الملف المصغَّر أكبر من الأصل بأكثر من 50 كيلوبايت، والتصغير يعمل بلا خطأ ولا تحذير.
العلاج سطر واحد في إعداد البناء: charset: 'utf8'، فيُخرج الأداة الحروف العربية كما هي. وشرطه أن يصل الملف بترويسة ترميز صحيحة من الخادم. ولأنّ الخطأ صامت ومكلف، وُضع في ملف البناء تعليق تحذيري ثابت بجانب الخيار يشرح سببه، حتى لا يحذفه أحد لاحقاً بحجّة أنّه «إعداد زائد».
وقع درس ثانٍ من الجنس نفسه في خيار الهدف (target). خفض الهدف إلى إصدار قديم من الجافاسكربت يدفع الأداة إلى «إنزال» الصيغ الحديثة مثل ?. و?? وتحويل كل استعمال منها إلى كود احتياطي أطول عدّة أضعاف. النتيجة تضخّم ملحوظ في الملف الرئيسي مقابل توافق لا قيمة له، لأنّ حزمة Firebase المستعملة تتطلّب أصلاً متصفّحات تدعم تلك الصيغ. فثُبِّت الهدف على esnext وعاد الحجم لطبيعته.
ومن الحكمة نفسها: التصغير في هذا المشروع يعمل بلا حزم (كل ملف يبقى مستقلاً)، لأنّ الحزم كان يغيّر التصديرات العالمية التي تعتمد عليها وسوم script والواجهة. كما استُثنيت ملفّات Service Worker من التصغير لأنّ لها نظام إصدارات خاصّاً، واستُثني ملف تهيئة Firebase لأنّه وحدة ES module تستورد من شبكة توصيل خارجية وقت التشغيل. الاستثناءات المقصودة جزء من الإعداد الصحيح، لا نقص فيه.
رؤوس الكاش: لكل نوع ملف عمرٌ مختلف
«اضبط الكاش» نصيحة بلا معنى حتى تُترجم إلى قيم لكل نوع ملف. هذه الرؤوس الفعلية المستعملة في استضافة المشروع، والمنطق وراء كل واحدة:
- ملفّات
jsوcss:public, max-age=31536000, immutable— سنة كاملة، وكلمةimmutableتعني «لا تسأل عنها مرّة أخرى حتى انتهاء المدّة». هذا مسموح فقط لأنّ كل رابط يحمل رقم إصدار في مسار الطلب، فأي تحديث ينشئ رابطاً جديداً بدل تعديل القديم. - الخطوط (
woff2وأمثالها): سنة كاملة معimmutableأيضاً — ملف الخطّ لا يتغيّر أبداً بعد إصداره، فمراجعته هدر خالص. - الصور:
public, max-age=2592000, immutable— ثلاثون يوماً فقط، لا سنة. السبب أنّ الصور تُستبدل أحياناً بالاسم نفسه (شعار محدَّث، أيقونة معدّلة) بلا تغيير رابطها، فالمدّة الأقصر سقفٌ لأسوأ حالة. - ملفّات
HTMLوالصفحة الرئيسية:no-cache, must-revalidate— بلا كاش. لأنّ ملف HTML هو الذي يحمل أرقام إصدارات كل الأصول؛ فإن كُوشِن هو، بقي المستخدم يطلب الإصدارات القديمة، ولن ينفعه أنّ الجديد منشور. - ملفّات Service Worker وملف الإصدار:
no-cache, no-store, must-revalidate— أشدّ درجة. هذه الملفّات ليست محتوى، بل آليّة الترقية نفسها؛ ونسخة مُكاشة منها تعني موقعاً عالقاً على إصدار قديم بلا طريقة لإخباره. ويُضاف لملف الـSW ترويسة النطاق المسموح ليعمل على كامل الموقع. - ملف بيان التطبيق (
manifest.json): ساعة واحدة مع مراجعة — وسطٌ بين الاثنين: لا حاجة لجلبه كل مرّة، ولا لتثبيته أسبوعاً.
القاعدة الجامعة في سطر: كل ملف يحمل إصداراً في رابطه يُكاش أطول مدّة ممكنة بلا مراجعة، وكل ملف يُقرّر أيّ إصدار يُحمَّل يجب أن يكون بلا كاش. أكثر الأعطال المحيّرة في النشر سببها خلط هذين الصنفين — تنشر تحديثاً وتراه على جهازك ولا يراه المستخدم أسبوعاً. تفصيل إدارة الإصدارات وإبطال الكاش في إدارة إصدارات Service Worker.
ودرس نشرٍ صغير مرتبط: ربط أمر البناء بخطوة ما قبل النشر في إعداد الاستضافة، فلا يمكن أن يُنشر الموقع بمجلّد مخرجات قديم لأنّ أحدهم نسي تشغيل البناء. الأتمتة أرخص من التذكّر.
تحميل الخطوط والأيقونات بلا حجب الرسم
كل ملف أنماط في الترويسة يحجب الرسم افتراضاً: المتصفّح لا يعرض شيئاً حتى ينزّله ويحلّله، لأنّه لا يريد أن يريك نصّاً بلا تنسيق. هذا صحيح للأنماط الأساسية، لكنّه خسارة صريحة لمكتبة أيقونات: أن يبقى المحتوى مخفياً بانتظار أيقونات زخرفية قرارٌ سيّئ.
الحيلة المستعملة في قوالب هذا الموقع: يُحمَّل ملف الأنماط غير الحرج بوسط طباعة عبر media="print"، فيراه المتصفّح غير مطابق للشاشة ويسحبه بأولوية منخفضة بلا حجب للرسم؛ وعند اكتمال تحميله يبدّل معالج onload="this.media='all'" الوسط إلى كل الوسائط، فتُطبَّق الأنماط فوراً. المكسب: يظهر المحتوى في موعده، وتلحق الأيقونات بعده بلحظة.
وللحيلة شرطٌ لا يجوز إغفاله: هي تعتمد على معالج حدث، فإن كان الجافاسكربت معطّلاً لم يُبدَّل الوسط ولم تُطبَّق الأنماط أبداً. لذلك يوضع بجانبها بديل داخل noscript يحمّل الملف نفسه بالطريقة العادية — سطر واحد يضمن ألّا تنكسر الصفحة عند من يعطّل السكربتات أو عند زاحف لا ينفّذها. أمّا ثمن الحيلة فهو ارتعاش بصري بسيط عند لحظة التبديل، ويُخفّف بحجز أبعاد ثابتة لمواضع الأيقونات، وبإضافة display=swap إلى رابط الخطوط ليظهر النصّ بخطّ النظام فوراً ثم يُستبدل.
وترتيب ما يُحمَّل أولاً يستحقّ قراراً واعياً لا ترتيباً عشوائياً. في صفحة التطبيق المذكور: ملف الأنماط المصغَّر أولاً، ثم تهيئة Firebase كوحدة ES module، ثم جسر التطبيق الأصلي (وهو خامل تماماً في المتصفّح ولا يعمل إلّا داخل النسخة المثبَّتة — انظر من موقع إلى تطبيق أندرويد بـCapacitor)، ثم طبقة الترجمة قبل الملف الرئيسي لأنّ الأخير يقرأ القواميس لحظة الإقلاع فيفشل إن سبقها، وتغطّي شاشة افتتاحية بسيطة الفراغ حتى تجهز الواجهة. الترتيب ليس تفصيلاً: عكس سطرين هنا يعني واجهة بنصوص ناقصة.
الاتصال المسبق (preconnect): وقتٌ حقيقي في أول رسم
قبل أن يصل أول بايت من نطاق جديد، يدفع المتصفّح ثلاث فواتير متسلسلة: ترجمة اسم النطاق، ثم إنشاء اتصال، ثم مصافحة التشفير. على اتصال جوال متوسّط قد تستهلك هذه الرحلات وحدها ما بين 300 و600 مليّ ثانية — قبل طلب أي محتوى. والأسوأ أنّ المتصفّح لا يبدؤها إلّا حين يكتشف الرابط أثناء تحليل الصفحة، أي متأخّراً.
وسم preconnect يقدّم هذه الفواتير ويسدّدها بالتوازي مع تحليل الصفحة، فلمّا يحين وقت الطلب الفعلي يكون الاتصال جاهزاً. في المشروع المذكور تُهيَّأ النطاقات الحرجة مسبقاً: نطاق قاعدة البيانات، ونطاق المصادقة، ونطاق تجديد رموز الجلسة — لأنّها تُطلب كلّها في الثانية الأولى من الإقلاع، فتوفير مصافحة لكل واحدة توفير مباشر في زمن أول شاشة مفيدة. وتُضاف dns-prefetch للنطاقات الأقلّ إلحاحاً (كالإشعارات وشبكة الملفّات الثابتة) لأنّها أرخص: ترجمة الاسم فقط بلا حجز اتصال.
وللاستعمال حدود واضحة. أولاً: crossorigin إلزامية للخطوط ولكل طلب يجري بنمط عابر للنطاقات، وإغفالها يفتح اتصالاً بمواصفات لا تطابق الطلب فيُهدر ويُفتح غيره. ثانياً: اقتصر على ثلاثة أو أربعة نطاقات حقيقية الأهمّية؛ فكل اتصال مفتوح يستهلك موارد ويزاحم الطلبات الحرجة على النطاق الترددي، وقائمة طويلة من preconnect تُبطّئ الصفحة بدل أن تسرّعها. القاعدة: هيّئ مسبقاً ما ستطلبه يقيناً في أول ثانية، ولا شيء غيره.
حذف رسائل التشخيص من نسخة الإنتاج
خطوة البناء في المشروع تحذف كل استدعاءات console وعبارات debugger من المخرجات، مع حذف التعليقات القانونية وإيقاف خرائط المصدر. الأثر مزدوج ومقصود.
الأثر الأول: الحجم. سطر التشخيص لا يحمل استدعاءً فقط، بل نصّاً وصفياً معه — وغالباً بالعربية في مشروع عربي. الحذف يشمل السطر بكامله بنصّه، وهو أحد أسباب انضغاط ملفّات المنطق بنسب عالية كما رأيت في الجدول. أمّا خرائط المصدر فتُركت مغلقة لتقليل عدد التحميلات وحجم ما يُنشر.
الأثر الثاني، والأهمّ: منع تسريب المعلومات. رسائل التشخيص أصدق دليل على بنية نظامك الداخلية: أسماء الحقول، أشكال البيانات، مسارات المجموعات في قاعدة البيانات، معرّفات المستخدمين، ونتائج فحوص الصلاحيات. وكونسول المتصفّح مفتوح لكل زائر بضغطة زر. من يريد استغلال نظامك يبدأ من هناك تحديداً، لأنّك تكون قد قدّمت له خريطة قاعدة بياناتك مجاناً. وهذا يجعل الحذف قراراً أمنياً قبل أن يكون قراراً في الأداء — ويكمّله ضبط قواعد الوصول على الخادم كما في قواعد Firestore الآمنة عملياً.
console.error أيضاً. فإن كنت تعتمد على رسائل الأخطاء في الكونسول لتشخيص أعطال المستخدمين، فقد فقدت وسيلتك الوحيدة وستصلك تقارير «لا يعمل» بلا أثر تتبعه. العلاج: مرّر أخطاءك عبر دالّة تسجيل خاصّة باسم غير console فلا يشملها الحذف، أو أرسلها إلى خدمة مراقبة قبل الوصول للكونسول. وأبقِ التشخيص كاملاً في نسخة التطوير — فملفّات المصدر تبقى كما هي، والحذف لا يقع إلّا في مخرجات البناء.
أسئلة شائعة
ما السرعة «الجيّدة» للموقع؟ استهدف ظهور المحتوى الرئيسي (LCP) خلال 2.5 ثانية على اتصال جوال متوسّط، ودرجة 90+ في PageSpeed Insights. الأهمّ هو الإحساس بالسرعة لدى الزائر الحقيقي.
هل أقلق من السرعة قبل النشر أم بعده؟ ابنِ بعادات سليمة من البداية (صور مضغوطة، كود نظيف)، ثم قِس وحسّن بعد النشر ببيانات حقيقية من Search Console وPageSpeed.
هل الإعلانات تبطّئ الموقع؟ نعم بعض الشيء، لذا احجز لها مساحة بأبعاد ثابتة لتجنّب قفز التخطيط (CLS)، ولا تُكثِر منها فوق المحتوى مباشرةً.
موقعي عربي وملفّاتي لا تنضغط كثيراً — هل الأداة سيّئة؟ لا، على الأرجح ملفّاتك محتوى لا منطق، والتصغير لا يمسّ النصوص. تحقّق أولاً من ترميز المخرجات: إن رأيت حروفاً عربية مكتوبة بصيغة هروب سادس عشري فأنت تدفع ستّة أضعاف حجم كل حرف، والعلاج ضبط الترميز على utf8. وإن كان الملف قاموس نصوص فعلاً، فالحلّ التقسيم والتحميل عند الطلب لا مزيد من التصغير.
ما المدّة الصحيحة للكاش؟ لا توجد مدّة واحدة. سنة مع immutable لكل أصل يحمل إصداراً في رابطه، شهر للصور التي قد تُستبدل بالاسم نفسه، وصفر لملفّات HTML وملفّات الـService Worker وملف الإصدار. إن اضطررت لاختيار مدّة واحدة لكل شيء، فأنت تحتاج أرقام إصدار في روابط أصولك أولاً.
خلاصة
ابدأ بالصور لأنها العائد الأكبر، ثم فعّل التحميل الكسول والكاش، حسِّن الخطوط، قلّل الطلبات، وراقب Core Web Vitals. خطوات متدرّجة، لكنّ أثرها مجتمعةً يحوّل موقعاً ثقيلاً إلى تجربة سريعة يحبّها المستخدم والمحرّك معاً.
والدرس الذي أضافته الأرقام الحقيقية: لا تحسّن بالحدس، وافهم طبيعة كل ملف قبل أن تختار له علاجاً. التصغير أعطى 29% من مجموع الحزمة مجاناً، لكنه أعطى 75% لملف منطق و7% فقط لقاموس نصوص — فعلاج الأول أداة بناء، وعلاج الثاني قرار معماري بالتقسيم والتحميل عند الطلب. وكذلك في الكاش: لا مدّة واحدة تصلح للجميع، بل عمر مختلف لكل نوع بحسب من يحمل الإصدار. أضِف إلى ذلك حذف التشخيص من الإنتاج (مكسب في الحجم والأمان معاً)، وتحميل غير الحرج بلا حجب الرسم، والاتصال المسبق بما ستطلبه يقيناً. اطبع جدول الأحجام في كل بناء، واجعل كل خيار في إعدادك قادراً على تبرير كلفته بالبايت — فالأداء ليس قائمة نصائح تُنفَّذ مرّة، بل رقمٌ تراقبه.