لو تطبيقك بيرسل bundle JavaScript بحجم 348KB مضغوط بـ gzip، Brotli على level 11 بيوصّله لـ 251KB بنفس الكود وبدون لمس الـ build. التحسين بيقع على شبكة الزائر — يعني وقت تحميل أقل، فاتورة CDN أرخص، و LCP أحسن في صفحات الـ landing.
Brotli vs gzip: مقارنة عملية لضغط أصول الويب
الـ gzip معاك من 1992. Brotli جاي من Google سنة 2015 ودخل الويب بشكل واسع 2017. النهارده 96% من المتصفحات الحديثة بتدعم Brotli على HTTPS حسب Can I Use 2026. الموضوع مش "هل أستخدمه"، السؤال "إزاي أستخدمه وعلى أي مستوى compression".
المشكلة باختصار
تطبيق Next.js عادي بعد build بيطلع ملف main.js حجمه 1,152KB raw. الـ CDN بيضغطه بـ gzip level 6 (الافتراضي) فيوصل لـ 348KB. لو بتخدم 50 ألف زائر شهريًا، التطبيق بيستهلك حوالي 16GB transfer. لو نزّلته لـ 251KB بـ Brotli level 11، بتدفع 12.5GB — يعني وفّرت 21% بدون كتابة سطر كود.
إيه اللي بيخلي Brotli أحسن من gzip
قبل التعريف العلمي، خد تشبيه واضح: تخيّل إنك بتنقل عفش. gzip بيبصّ على الكرتونة اللي قدامه بس وبيشوف هل في حاجة مكررة جواها — مثلًا يلاقي كلمة "function" مكتوبة 80 مرة في الملف فيخزّنها مرة واحدة. Brotli معاه قاموس جاهز فيه أكتر من 13,000 كلمة وعبارة شائعة في الويب (HTML tags، CSS properties، JavaScript keywords) — يعني قبل ما يبدأ يضغط، عنده "غش" جاهز قبل ما يفتح أول كرتونة.
التعريف العلمي: Brotli بيستخدم خوارزمية مركبة من LZ77 + Huffman coding + 2nd-order context modeling مع static dictionary حجمه 122,784 byte. الـ static dictionary ده هو السر — gzip ما عندوش حاجة زيها، فبيبدأ من الصفر مع كل ملف. تفاصيل المواصفة موجودة في RFC 7932.
أرقام حقيقية: قياس على bundle Next.js
قياس فعلي على ملف main.js حجمه 1,152KB من production build:
- gzip level 6 (default): 348KB — وقت ضغط 84ms
- gzip level 9 (max): 339KB — وقت ضغط 280ms
- Brotli level 4: 296KB — وقت ضغط 38ms
- Brotli level 6: 268KB — وقت ضغط 95ms
- Brotli level 11 (max): 251KB — وقت ضغط 4,200ms
ركز في الأرقام دي: Brotli level 11 بيضغط أحسن لكن بياخد 50× وقت gzip level 6. مفيش معنى تستخدمه على الفلاي مع كل request. الحل العملي اسمه Brotli static — تضغط مرة واحدة في الـ CI وتخدم الملف الجاهز.
إعداد NGINX: Brotli static + dynamic
# /etc/nginx/nginx.conf
load_module modules/ngx_http_brotli_filter_module.so;
load_module modules/ngx_http_brotli_static_module.so;
http {
# static: يخدم الملفات اللي ضغطتها مسبقًا في build
brotli_static on;
# dynamic: يضغط responses حية (APIs مثلًا) بمستوى أخف
brotli on;
brotli_comp_level 4;
brotli_min_length 1024;
brotli_types text/plain text/css application/javascript
application/json image/svg+xml;
# احتفظ بـ gzip للمتصفحات الأقدم (4% فقط)
gzip on;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_types text/plain text/css application/javascript
application/json image/svg+xml;
}