تصغير حمولات الشبكة وضغطها باستخدام brotli

هذا الدرس التطبيقي حول الترميز هو امتداد لعملية تقليل أحمال الشبكة وضغطها. درس تطبيقي حول الترميز ويفترض أنك على دراية بمفاهيم الضغط الأساسية. بالنسبة مقارنةً بخوارزميات الضغط الأخرى مثل gzip، يستكشف هذا الدرس التطبيقي حول الترميز كيفية يمكن أن يؤدي ضغط Brotli إلى تقليل نِسب الضغط وتحسين أداء تطبيقك بشكل عام الحجم.

لقطة شاشة التطبيق

القياس

قبل التعمق في إضافة التحسينات، يُفضل دائمًا تحليل الحالة الحالية للتطبيق.

  1. انقر على إنشاء ريمكس لتعديل لجعل المشروع قابلاً للتعديل.
  2. لمعاينة الموقع الإلكتروني، اضغط على عرض التطبيق. ثم اضغط ملء الشاشة ملء الشاشة

في القسم السابق تصغير وضغط حمولات الشبكة درس تطبيقي حول الترميز تم تقليل حجم main.js من 225 كيلوبايت إلى 61.6 كيلوبايت. في هذا الدرس التطبيقي حول الترميز، كيف يمكن لضغط 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 الديناميكي

يمكنك الآن رؤية تطبيق brotli من bz في العنوان Content-Encoding. تم خفض main.bundle.js من 225 كيلوبايت إلى 53.1 كيلوبايت! هذا الرقم أصغر بنسبة% 14 تقريبًا مقارنةً بـ gzip (61.6 كيلوبايت).

الضغط الثابت

تكمن الفكرة وراء الضغط الثابت في ضغط مواد العرض وحفظها مسبقًا محددة.

الإيجابيات

  • لم يعُد وقت الاستجابة بسبب مستويات الضغط العالية مصدر قلق. لا شيء على الفور لضغط الملفات حيث يمكن جلبها مباشرةً.

السلبيات

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

ضغط ثابت مع Node/Express وwebpack

بما أنّ الضغط الثابت يتضمّن ضغط الملفات مسبقًا، يجب استخدام 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.

  1. انقر على زر الأدوات.
  2. انقر على الزر وحدة التحكّم.
  3. في وحدة التحكّم، شغِّل الأوامر التالية لتغييرها إلى public. الدليل وعرض كل ملفاته:
cd public
ls -lh
حجم الحزمة مع ضغط Brotli الثابت

تم حفظ نسخة brotli المضغوطة من الحزمة، main.bundle.js.br هنا أيضًا وهو أصغر حجمًا بنسبة 76% تقريبًا (225 كيلوبايت مقابل 53 كيلوبايت) من main.bundle.js

بعد ذلك، اطلب من الخادم إرسال هذه الملفات المضغوطة باستخدام brotli عند الحاجة يتم طلب إصدارات JavaScript الأصلية. ويمكن القيام بذلك من خلال تحديد نوع المسار في 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 من خلال التحقق من يتضمن عنوان طلب 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'));

بعد إعادة تحميل التطبيق، ألقِ نظرة على لوحة "الشبكة" مرة أخرى.

حجم الحزمة 53.1 كيلوبايت (من 225 كيلوبايت)

اكتمال عملية النقل بنجاح لقد استخدمت ضغط Brotli لضغط مواد العرض بشكل أكبر.

الخاتمة

يوضّح هذا الدرس التطبيقي حول الترميز كيف يمكن لـ brotli تقليل إجمالي أداء تطبيقك الحجم. حيثما أمكن، تعد خوارزمية الضغط brotli أكثر فعالية من gzip