הקטנה ודחיסה של מטענים ייעודיים (payload) ברשת באמצעות brotli

Michael DiBlasio
Michael DiBlasio

ה-Codelab הזה הוא הרחבה של המטענים הייעודיים (payloads) של הרשת: הקטנה ודחוס של הנתונים Codelab ומבוססת על ההנחה שאתם מכירים את המושגים הבסיסיים של דחיסה. בתור בהשוואה לאלגוריתמים אחרים של דחיסה כמו gzip, ה-Codelab הזה בוחן איך דחיסת Brotli יכולה לצמצם עוד יותר את יחסי הדחיסה ואת הגודל הכולל של האפליקציה גודל.

צילום מסך של אפליקציה

מדידה

לפני שממשיכים להוסיף אפשרויות אופטימיזציה, תמיד כדאי לנתח את המצב הנוכחי של האפליקציה.

  1. לוחצים על רמיקס לעריכה כדי לערוך את הפרויקט.
  2. כדי לראות תצוגה מקדימה של האתר, לוחצים על הצגת האפליקציה. לאחר מכן לוחצים על מסך מלא מסך מלא.

בגרסה הקודמת, הקטנה ודחוס של מטענים ייעודיים (payloads) של רשת, Codelab, הורדנו את הגודל של main.js מ-225KB ל-61.6KB. ב-Codelab הזה נבדוק איך דחיסת Brotli יכולה לצמצם עוד יותר את גודל החבילה.

דחיסה של Brotli

ברוטלי הוא אלגוריתם דחיסה חדש יותר שיכול לספק דחיסת טקסט טובה יותר תוצאות מאשר gzip. לפי CertSimple, ביצועי Brotli הם:

  • קטן ב-14% מ-gzip ל-JavaScript
  • קטן ב-21% מ-gzip ל-HTML
  • קטן ב-17% מ-gzip לשירות CSS

כדי להשתמש ב-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 אחראי להגדרת שרת ה-Node שמארח את האפליקציה.

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 (והקבצים האלה נוצרים על ידי Webpack בכל גרסת build).

כדי לוודא שכל הנכסים יידחסו באמצעות 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 הופחת מ-225KB ל-53.1KB! הקטנה ב-14% בערך בהשוואה ל-gzip (61.6KB).

דחיסה סטטית

הרעיון שעומד מאחורי דחיסה סטטית הוא נכסים דחוסים ויישמרו מראש הזמן.

יתרונות

  • זמן אחזור בגלל רמות דחיסה גבוהות כבר לא מדאיג. שום דבר צריך להתרחש בזמן אמת כדי לדחוס קבצים, כי עכשיו אפשר לאחזר אותם ישירות.

חסרונות

  • צריך לדחוס את הנכסים בכל גרסת build. זמן היצירה יכול להתארך באופן משמעותי אם משתמשים ברמות דחיסה גבוהות.

דחיסה סטטית באמצעות Node/Express ו-webpack

דחיסה סטטית כוללת דחיסת קבצים מראש, ולכן ה-webpack אפשר לשנות את ההגדרות כדי לדחוס נכסים כחלק משלב ה-build. אפשר להשתמש בbrotli-webpack-plugin בשביל זה.

כדי להתחיל, צריך להוסיף אותו בתור devDependency ב-package.json:

"devDependencies": {
  //...
 "brotli-webpack-plugin": "^1.1.0"
},

כמו כל פלאגין אחר של Webpack, מייבאים אותו בקובץ התצורות, 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 כדי לראות מה יש במשחק הגמר ספריית public/ שמוצגת על ידי שרת ה-Node.

  1. לוחצים על הלחצן כלים.
  2. לוחצים על הלחצן Console.
  3. במסוף, מריצים את הפקודות הבאות כדי לשנות אותן אל public ולראות את כל הקבצים שלה:
cd public
ls -lh
גודל חבילה עם דחיסת Brotli סטטית

גרסת ה-Brotli הדחוסה של החבילה, main.bundle.js.br, נשמרה עכשיו גם כאן הוא קטן ב-76% (225KB לעומת 53KB) מאשר 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' כארגומנט הראשון, הפעולה הזאת פועלת בכל נקודת הקצה (endpoint) שמופעלת כדי לאחזר קובץ 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.1KB (מ-225KB)

הצלחת! השתמשת בדחיסת Brotli כדי לדחוס עוד יותר את הנכסים שלך!

סיכום

ה-Codelab הזה ממחיש איך brotli יכול לצמצם עוד יותר את העלות הכוללת של האפליקציה גודל. כשהאפשרות נתמכת, brotli הוא אלגוריתם דחיסה חזק יותר מאשר gzip.