هذا الدرس التطبيقي حول الترميز هو إضافة إلى الدرس التطبيقي حول ترميز حمولات الشبكة
وضغطها ويفترض أنّك على دراية بمفاهيم الضغط الأساسية. مقارنةً بخوارزميات الضغط الأخرى مثل gzip
، يستكشف هذا الدرس التطبيقي حول الترميز كيف يمكن لضغط Brotli تقليل نسب الضغط والحجم الإجمالي لتطبيقك.
قياس
قبل الشروع في إضافة تحسينات، من الجيد دائمًا تحليل الحالة الراهنة للتطبيق.
- انقر على إنشاء ريمكس لتعديل لجعل المشروع قابلاً للتعديل.
- لمعاينة الموقع الإلكتروني، اضغط على عرض التطبيق، ثم اضغط على ملء الشاشة .
في الدرس التطبيقي السابق حول ترميز
حمولات الشبكة وضغطها،
خفّضنا حجم main.js
من 225 كيلوبايت إلى 61.6 كيلوبايت. في هذا الدرس التطبيقي حول الترميز، ستكتشف
كيف يمكن لضغط Brotli تقليل حجم الحزمة بشكل أكبر.
ضغط Brotli
Brotli
هي خوارزمية ضغط أحدث يمكنها تقديم نتائج ضغط أفضل من gzip
. وفقًا لـ CertSimple، فإن أداء Brotli هو:
- أصغر من
gzip
بنسبة 14% للغة JavaScript - أصغر بنسبة 21% من
gzip
لـ HTML - أصغر بنسبة% 17 من
gzip
لخدمة مقارنة الأسعار
لاستخدام Brotli، يجب أن يكون خادمك متوافقًا مع HTTPS. يتوافق تطبيق Brotli مع أحدث إصدارات معظم المتصفّحات. في المتصفّحات
التي تتوافق مع Brotli سيتم تضمين br
في عناوين Accept-Encoding
:
Accept-Encoding: gzip, deflate, br
يمكنك تحديد خوارزمية الضغط التي يتم استخدامها عن طريق الحقل Content-Encoding
في علامة التبويب "الشبكة" من أدوات مطوّري برامج Chrome (Command+Option+I
أو Ctrl+Alt+I
):
تفعيل Brotli
الضغط الديناميكي
يتضمّن الضغط الديناميكي ضغط مواد العرض بشكلٍ فوري عند طلبها من المتصفّح.
الإيجابيات
- لا حاجة إلى إنشاء وتحديث النُسخ المضغوطة المحفوظة من مواد العرض.
- يناسب ضغط الملفات بشكل فوري صفحات الويب التي يتم إنشاؤها ديناميكيًا.
السلبيات
- يستغرق ضغط الملفات على مستويات أعلى للحصول على نِسب ضغط أفضل وقتًا أطول. وقد يؤدّي ذلك إلى نتيجة أداء بينما ينتظر المستخدم ضغط مواد العرض قبل إرسالها من خلال الخادم.
الضغط الديناميكي باستخدام Node/Express
يكون الملف server.js
مسؤولاً عن إعداد خادم العُقدة الذي يستضيف التطبيق.
var express = require('express');
var app = express();
app.use(express.static('public'));
var listener = app.listen(process.env.PORT, function() {
console.log('Your app is listening on port ' + listener.address().port);
});
وكل ذلك في الوقت الحالي هو استيراد express
واستخدام البرمجيات الوسيطة express.static
لتحميل جميع ملفات HTML وJS وCSS الثابتة في
public/directory
(ويتم إنشاء هذه الملفات بواسطة حزمة الويب مع كل إصدار).
للتأكّد من ضغط جميع مواد العرض باستخدام brotli في كل مرة يتم فيها
طلبها، يمكن استخدام
وحدة shrink-ray
. ابدأ بإضافته كـ devDependency
في package.json
:
"devDependencies": {
//...
"shrink-ray": "^0.1.3"
},
واستيراده إلى ملف الخادم، server.js
:
var express = require('express');
var shrinkRay = require('shrink-ray');
ويمكنك إضافتها كبرمجية وسيطة قبل تثبيت express.static
:
//...
var app = express();
// compress all requests
app.use(shrinkRay());
app.use(express.static('public'));
أعِد تحميل التطبيق الآن وألق نظرة على حجم الحزمة في لوحة "الشبكة":
يمكنك الآن رؤية تطبيق brotli
من bz
في العنوان Content-Encoding
.
تم خفض main.bundle.js
من 225 كيلوبايت إلى 53.1 كيلوبايت! وهو أصغر بنسبة 14% تقريبًا
مقارنةً بـ gzip
(61.6 كيلوبايت).
الضغط الثابت
تكمن الفكرة وراء الضغط الثابت في ضغط الأصول وحفظها مسبقًا.
الإيجابيات
- لم يعُد وقت الاستجابة بسبب مستويات الضغط العالية مصدر قلق. ولا يلزم حدوث أي شيء بشكل فوري لضغط الملفات حيث يمكن الآن جلبها مباشرةً.
السلبيات
- يجب ضغط مواد العرض مع كل إصدار. يمكن أن تزداد مدة الإنشاء بشكل كبير في حالة استخدام مستويات ضغط عالية.
ضغط ثابت مع Node/Express وwebpack
بما أنّ الضغط الثابت يتضمّن ضغط الملفات في وقت مبكر، يمكن تعديل إعدادات حزمة الويب لضغط مواد العرض كجزء من خطوة الإنشاء. ويمكن استخدام
brotli-webpack-plugin
لذلك.
ابدأ بإضافته كـ devDependency
في package.json
:
"devDependencies": {
//...
"brotli-webpack-plugin": "^1.1.0"
},
مثل أي مكوّن إضافي آخر لحزمة الويب، عليك استيراده في ملف الإعدادات،
webpack.config.js
:
var path = require("path");
//...
var BrotliPlugin = require('brotli-webpack-plugin');
وقم بتضمينه في صفيف المكونات الإضافية:
module.exports = {
// ...
plugins: [
// ...
new BrotliPlugin({
asset: '[file].br',
test: /\.(js)$/
})
]
},
تستخدم مصفوفة المكوّن الإضافي الوسيطات التالية:
asset
: اسم مادة العرض المستهدَفة- تم استبدال
[file]
باسم ملف مادة العرض الأصلي. test
: تتم معالجة جميع مواد العرض التي تتطابق مع هذا التعبير العادي (أي مواد عرض JavaScript التي تنتهي بـ.js
).
على سبيل المثال، ستتم إعادة تسمية main.js
إلى main.js.br
.
وعند إعادة تحميل التطبيق وإعادة إنشائه، يتم الآن إنشاء نسخة مضغوطة من الحزمة الرئيسية. افتح Glitch Console لإلقاء نظرة على محتوى الدليل
public/
الأخير الذي يعرضه خادم Node.
- انقر على زر الأدوات.
- انقر على الزر وحدة التحكّم.
- في وحدة التحكّم، شغِّل الأوامر التالية للتغيير إلى دليل
public
والاطّلاع على كل ملفاته:
cd public
ls -lh
تم حفظ نسخة brotli المضغوطة من الحزمة، main.bundle.js.br
،
هنا أيضًا، كما أنها أصغر حجمًا بنسبة 76% (225 كيلوبايت مقابل 53 كيلوبايت) من
main.bundle.js
.
بعد ذلك، يمكنك أن تطلب من الخادم إرسال هذه الملفات المضغوطة باستخدام brotli عند طلب إصدارات JS الأصلية. ويمكن إجراء ذلك من خلال تحديد مسار جديد في server.js
قبل عرض الملفات باستخدام express.static
.
var express = require('express');
var app = express();
app.get('*.js', (req, res, next) => {
req.url = req.url + '.br';
res.set('Content-Encoding', 'br');
res.set('Content-Type', 'application/javascript; charset=UTF-8');
next();
});
app.use(express.static('public'));
يتم استخدام app.get
لإخبار الخادم بكيفية الاستجابة لطلب GET
لنقطة نهاية محدّدة. يتم بعد ذلك استخدام دالة الاستدعاء لتحديد كيفية التعامل مع هذا الطلب. ويعمل المسار على النحو التالي:
- عند تحديد
'*.js'
كوسيطة أولى، يعني ذلك أنّ هذه الطريقة تعمل مع كل نقطة نهاية يتم تنشيطها لاسترجاع ملف JS. - ضمن طلب معاودة الاتصال، يتم إرفاق
.br
بعنوان URL للطلب ويتم ضبط عنوان الاستجابةContent-Encoding
علىbr
. - تم ضبط عنوان
Content-Type
علىapplication/javascript; charset=UTF-8
لتحديد نوع MIME. - وأخيرًا، يضمن
next()
استمرار التسلسل مع أي استدعاء قد يكون بعد ذلك.
بما أنّ بعض المتصفّحات قد لا تتوافق مع ضغط brotli، يُرجى التأكّد من أنّ brotli متوافق قبل عرض الملف المضغوط باستخدام brotli من خلال التحقّق من
أن عنوان طلب Accept-Encoding
الذي يتضمن br
:
var express = require('express');
var app = express();
app.get('*.js', (req, res, next) => {
if (req.header('Accept-Encoding').includes('br')) {
req.url = req.url + '.br';
console.log(req.header('Accept-Encoding'));
res.set('Content-Encoding', 'br');
res.set('Content-Type', 'application/javascript; charset=UTF-8');
}
next();
});
app.use(express.static('public'));
بعد إعادة تحميل التطبيق، ألقِ نظرة على لوحة "الشبكة" مرة أخرى.
اكتمال عملية النقل بنجاح لقد استخدمت ضغط Brotli لضغط مواد العرض بشكل أكبر.
الخلاصة
يوضّح هذا الدرس التطبيقي حول الترميز كيف يمكن لتطبيق brotli
تقليل الحجم الإجمالي لتطبيقك. تُعد brotli
خوارزمية ضغط أكثر فعالية من gzip
في حال توفّرها.