شعار أوسكار أوسكار كل المقالات

تصغير كود عربي بـ esbuild: إعداد واحد يوفّر عشرات الكيلوبايتات

أضفنا خطوة تصغير لملفّات مشروع عربي كبير، وتوقّعنا النتيجة المعتادة: ملفّات أصغر بثلث أو نصف. ما حدث أن الملف الرئيسي تضخّم. لا نقص قليل في التوفير، بل زيادة صريحة على الحجم الأصلي. وأداة التصغير لم تُبلّغ عن أي خطأ — عملت بنجاح وأعطت ملفاً أكبر.

السبب إعداد واحد افتراضي لا يلاحظه أحد يكتب بالإنجليزية. وحين ضبطناه انقلبت النتيجة تماماً. هذه القصة، ومعها أرقام بناء حقيقية من مشروع إنتاجي تشرح شيئاً أعمق: لماذا ينضغط ملف بنسبة 75% وآخر في نفس المشروع بـ 7% فقط.

السبب: تهريب المحارف غير اللاتينية

أدوات التصغير تُهرِّب افتراضياً كل محرف خارج نطاق ASCII إلى تسلسل هروب من صيغة \uXXXX. الغرض أمان توافقي: ضمان أن الملف يُقرأ صحيحاً حتى لو أُرسل بترميز خاطئ أو مرّ بوسيط قديم لا يحترم الترميز.

الحساب البسيط يوضح الكارثة. الحرف العربي الواحد في ترميز UTF-8 يشغل بايتين. وبعد التهريب يصبح ستّة محارف ASCII — أي ستّة بايتات. النتيجة: كل نصّ عربي في مشروعك يتضاعف حجمه ثلاث مرّات.

وفي تطبيق معرَّب بالكامل، النصوص العربية ليست تفصيلاً هامشياً: رسائل الواجهة، وقوائم المحتوى، والتنبيهات، وأسماء الأشهر، وكل نصّ يراه المستخدم. في مشروعنا كان أثر هذا الإعداد وحده يقارب خمسين كيلوبايتاً زائدة على ملف واحد.

الحلّ: سطر واحد

charset: 'utf8'

هذا كل شيء. يُخبر الأداة أن تُخرج المحارف كما هي بترميز UTF-8 بدل تهريبها. والشرط الوحيد الذي يجعله آمناً موجود عندك أصلاً: أن يُخدَّم الملف بترميز صحيح — وهو ما تفعله كل استضافة حديثة تلقائياً لملفّات .js و.css.

قاعدة: إن كان مشروعك يحوي نصوصاً عربية داخل الكود، فاضبط charset على utf8 صريحاً قبل أي تحسين أداء آخر. هو أرخص توفير في المشروع كلّه: سطر واحد بلا أي مفاضلة.

الأرقام الحقيقية — والدرس المخفيّ فيها

هذه مخرجات بناء فعلية لمشروع عربي إنتاجي بعد ضبط الإعداد. لا تقرأ العمود الأخير كمقياس جودة، بل كخريطة لما يقبل التصغير وما لا يقبله:

  • ملف الحماية والتفاعل: 8.9KB2.2KB — انضغاط 75%
  • جسر الاتصال بالتطبيق الأصلي: 15.2KB4.7KB69%
  • وحدة تخزين الصور: 21.5KB8.5KB60%
  • منتقي التواريخ: 8.3KB4.7KB43%
  • الملف الرئيسي للتطبيق: 384KB253.5KB34%
  • محرّك الترجمة: 36.9KB26.9KB27%
  • نصوص واجهة الترجمة: 27.2KB24.3KB11%
  • قاموس المحتوى المترجَم: 79.1KB73.7KB7% فقط

الفارق بين 75% و7% ليس عيباً في الأداة. التصغير يعمل على ثلاثة أشياء: يحذف المسافات والتعليقات، ويقصّر أسماء المتغيّرات المحلّية، ويحذف الكود الميّت. ولا يستطيع لمس محتوى النصوص — فالنصّ داخل علامات التنصيص جزء من سلوك البرنامج لا من شكله.

ملف الحماية كله منطق وأسماء متغيّرات، فانضغط 75%. وقاموس المحتوى المترجَم كله جُمَل عربية طويلة داخل تنصيص، فلا يوجد فيه ما يُصغَّر أصلاً — الـ7% كانت المسافات والتعليقات والبنية المحيطة فقط.

استنتاج عملي: نسبة التصغير المنخفضة في ملف نصوص ليست مشكلة تُحلّ، بل حدّ طبيعي. علاج ملفّات النصوص الضخمة ليس التصغير بل التقسيم والتحميل عند الطلب: لا تُحمّل قاموس اللغة الثانية لمن يقرأ بالأولى.

إعدادات أخرى تصنع فرقاً ملموساً

حذف رسائل التشخيص من نسخة الإنتاج:

drop: ['console', 'debugger']

يُزيل كل نداءات console.* وكل عبارات debugger. الفائدة مزدوجة: ملف أصغر، ومنعُ تسريب معلومات تشخيصية للمستخدم. لكن انتبه لأثر جانبي حقيقي: أي نداء console كنت تعتمد عليه لتسجيل خطأ في الإنتاج سيختفي أيضاً — فسجّل الأخطاء المهمّة بطريقة أخرى لا بالوحدة النصّية.

خرائط المصدر: إبقاؤها مغلقة يقلّل عدد الملفّات المحمّلة وحجم النشر. المفاضلة أن تشخيص خطأ في الإنتاج يصبح أصعب. حلّ وسط عملي: ولّدها لكن لا تنشرها علناً — احتفظ بها لديك لفكّ رموز تقارير الأخطاء.

اختيار الهدف: ضبط الهدف على أحدث صيغة تدعمها متصفّحاتك يتفادى تضخّماً غير متوقّع. حين تطلب هدفاً قديماً، تُترجم الأداة الصيغ الحديثة إلى بدائل مطوّلة — فالمعامل المختصر مثل ?. و?? يتحوّل إلى شروط متداخلة تتكرّر مئات المرّات في ملف كبير. إن كانت مكتباتك تفترض متصفّحاً حديثاً أصلاً، فالتهبيط تكلفة بلا مقابل.

حذف التعليقات القانونية: إعداد صغير يحذف كتل التراخيص المطوّلة من الملف الناتج. راجع تراخيص مكتباتك أولاً — بعضها يشترط إبقاء إشعار حقوقه.

تصغير فقط، بلا حزم — ومتى يصحّ ذلك

الأدوات الحديثة تفعل شيئين مختلفين: الحزم (دمج الوحدات ومتابعة الاستيرادات في ملف واحد) والتصغير (تقليص النصّ). في مشروعنا اخترنا التصغير بلا حزم: كل ملف يُصغَّر مستقلاً ويحتفظ بمساره.

يصحّ هذا الخيار في حالة محدّدة: كود قائم يُحمَّل بوسوم script عادية بلا نظام وحدات، وترتيب التحميل معروف ومستقرّ. الفائدة أن خطوة البناء تبقى بسيطة جدّاً وسريعة — عندنا تكتمل في أقلّ من أربع ثوانٍ لعشرة ملفّات جافاسكربت وملفَّي أنماط.

ومتى تحتاج الحزم فعلاً؟ حين تستخدم نظام وحدات، أو تحتاج إزالة الكود غير المستخدَم من مكتبات كبيرة، أو تريد تقسيم الحِزَم لتحميل عند الطلب. لا تدفع تعقيد الحزم قبل أن تحتاجه.

ما لا يُصغَّر أبداً: ملفّات Service Worker

هذا استثناء تعلّمناه بالطريقة الصعبة. ملفّات العامل الخدمي تُستثنى من التصغير كلّياً، لسببين:

  1. لها آلية إصدار خاصّة. ملفّ العامل الخدمي يحمل ثابت إصدار داخله يُغيَّر يدوياً مع كل نشر، والمتصفّح يقارن محتوى الملف حرفياً ليقرّر هل يوجد تحديث. تمرير الملف على أداة تصغير يجعل المحتوى متغيّراً بطرق لا تتحكّم فيها، فتنكسر مطابقة الإصدار — والتفصيل كامل في إدارة إصدارات Service Worker.
  2. يُخدَّم من الجذر بمساره الحرفي. نطاق سيطرة العامل الخدمي يُحدّده مسار ملفّه، ونقله إلى مجلّد المخرجات يقلّص نطاقه فيتوقّف عن التحكّم في بقيّة الموقع.

القاعدة العامة المستخلصة: أي ملف يُطابَق محتواه أو مساره من خارج بنائك يجب أن يُستثنى من خطوة البناء — ملفّات العامل الخدمي، وملفّات التحقّق من الملكية، وملفّات تصريح البائعين.

اطبع جدول الأحجام مع كل بناء

أهمّ ممارسة في هذا الملف كلّه ليست إعداداً بل عادة: اجعل خطوة البناء تطبع جدولاً بالحجم قبل وبعد ونسبة التوفير لكل ملف. أسطر قليلة تقرأ حجم المصدر والمخرَج وتطبع المقارنة.

القيمة ليست في الجدول بل في أنه يجعل الانحراف مرئياً فوراً. لولا هذا الجدول لما اكتشفنا مشكلة التهريب أصلاً — كنّا سننشر ملفّاً أكبر بخمسين كيلوبايتاً ونحن مطمئنّون أننا «فعّلنا التصغير». وهو نفس الدرس الذي واجهناه في قياس الإعلانات: قِس ما يهمّ لا ما يُطمئن.

أسئلة شائعة

هل التصغير يكفي أم أحتاج ضغط الخادم؟ الاثنان معاً وليسا بديلين. التصغير يقلّل المحتوى، وضغط النقل (Gzip أو Brotli) يقلّل ما يُرسل على الشبكة. الضغط يعالج تكرار النصوص جيّداً، لذا الفارق الصافي لملفّات النصوص أقلّ مما يبدو من الأرقام الخام — لكنه لا يُغني عن ضبط الترميز.

هل يفسد التصغير الكود العربي؟ لا، النصوص لا تُمَسّ محتوىً. المشكلة كانت في تمثيلها على القرص فقط. تحقّق بفتح الملف الناتج: إن رأيت ا بدل الحرف العربي فالإعداد غير مضبوط.

هل أصغّر ملفّات الأنماط أيضاً؟ نعم، وبنفس الاعتبار: ملف أنماط يحوي محتوى عربياً في خصائص مثل content يخضع لنفس مشكلة التهريب. لكن التوفير في الأنماط أقلّ عادةً لأن بنيتها أصلاً مكثّفة — راجع كيف تكتب CSS نظيفاً.

هل أرفع الملفّات المصغّرة إلى المستودع؟ استثنِ مجلّد المخرجات وولّده في كل نشر. إبقاؤه متتبَّعاً يُنتج تعارضات في كل التزام ويضاعف حجم المستودع بلا فائدة.

خلاصة

سطر charset: 'utf8' هو أرخص تحسين أداء يمكن أن تجريه على مشروع عربي: بلا مفاضلة، وبلا خطر، وبتوفير يقارب ثلث حجم كل نصوصك. أضِف إليه حذف رسائل التشخيص من الإنتاج، وهدفاً حديثاً يتفادى تهبيطاً لا تحتاجه، واستثناءً صريحاً لملفّات العامل الخدمي.

والدرس الذي يبقى بعد الإعدادات: لا تثق بأن التحسين حسّن. اطبع الأرقام قبل وبعد، فالتصغير الذي يضخّم ملفّك يعمل بنجاح تامّ ولا يخبرك بشيء.