ה-Codelab הזה הוא הרחבה של ה-codelab Minify ודחיסה של מטענים ייעודיים (payloads) ברשת, ומבוססת על ההנחה שאתם מכירים את המושגים הבסיסיים של דחיסה. בהשוואה לאלגוריתמים אחרים של דחיסה כמו gzip
, ה-Codelab הזה בודק איך דחיסת Brotli (br
) יכולה לצמצם עוד יותר את יחסי הדחיסה ואת הגודל הכולל של האפליקציה.
מדידה
לפני שמתחילים להוסיף אופטימיזציות, תמיד מומלץ לנתח קודם את המצב הנוכחי של האפליקציה.
- לוחצים על Remix to Edit כדי לאפשר עריכה של הפרויקט.
- כדי לראות תצוגה מקדימה של האתר, לוחצים על הצגת האפליקציה. לאחר מכן לוחצים על מסך מלא .
בגרסה הקודמת של Minify ו-דחיסה של מטענים ייעודיים (payloads) ברשת, צמצמנו את הגודל של main.js
מ-225KB ל-61.6KB. בסדנת הקוד הזו תלמדו איך דחיסת Brotli יכולה להקטין עוד יותר את גודל החבילה.
דחיסת 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
הדרך שבה מגדירים שרת אינטרנט לשליחת משאבים בקידוד Brotli תלויה באיך אתם מתכננים לקודד אותם. יש לכם אפשרות לדחוס משאבים באופן דינמי באמצעות Brotli בזמן הבקשה (דינמי), או לקודד אותם מראש כך שהם כבר יהיו דחוסים עד שהמשתמש יבקש אותם (סטטי).
דחיסת נתונים דינמית
דחיסת נתונים דינמית כוללת דחיסת נכסים בזמן אמת, כשהם מופיעים בבקשות מהדפדפן.
יתרונות
- אין צורך ליצור ולעדכן גרסאות דחוסות של נכסים שנשמרו.
- דחיסה בזמן אמת עובדת טוב במיוחד בדפי אינטרנט שנוצרים באופן דינמי.
חסרונות
- דחיסת קבצים ברמות גבוהות יותר כדי להשיג יחסי דחיסה טובים יותר נמשכת זמן רב יותר. המצב הזה עלול לגרום להיט של הביצועים, כי המשתמש ממתין שהנכסים יידחסו לפני שהם נשלחים על ידי השרת.
דחיסת נתונים דינמית באמצעות Node ו-Express
הקובץ server.js
אחראי להגדרת שרת Node שמארח את האפליקציה.
const express = require('express');
const app = express();
app.use(express.static('public'));
const 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
:
const express = require('express');
const shrinkRay = require('shrink-ray');
ומוסיפים אותו כתוכנה לעיבוד נתונים (middleware) לפני שמרכז הנתונים express.static
מוצמד:
// ...
const app = express();
// Compress all requests
app.use(shrinkRay());
app.use(express.static('public'));
עכשיו טוענים מחדש את האפליקציה ובודקים את גודל החבילה בחלונית Network (רשת):
עכשיו אפשר לראות שהאפקט brotli
הוחל מ-bz
בכותרת Content-Encoding
.
main.bundle.js
ירד מ-225KB ל-53.1KB! הגודל הזה קטן ב-14% לעומת gzip
(61.6KB).
דחיסה סטטית
הרעיון מאחורי דחיסת נתונים סטטית הוא לדחוס ולשמור את הנכסים מראש.
יתרונות
- זמן האחזור שנגרם מרמות דחיסה גבוהות כבר לא מהווה בעיה. לא צריך שיקרה שום דבר בזמן אמת כדי לדחוס קבצים, כי עכשיו אפשר לאחזר אותם ישירות.
חסרונות
- צריך לדחוס את הנכסים בכל גרסת build. אם משתמשים ברמות דחיסה גבוהות, זמני ה-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
: כל הנכסים שתואמים ל-RegExp הזה (כלומר, נכסי JavaScript שמסתיימים ב-.js
) עוברים עיבוד.
לדוגמה, השם main.js
ישתנה ל-main.js.br
.
כשהאפליקציה נטענת מחדש ונבנית מחדש, נוצרת עכשיו גרסה דחוסה של החבילה הראשית. פותחים את Glitch Console כדי לראות מה נמצא בספרייה public/
הסופית שמוצגת על ידי שרת Node.
- לוחצים על הלחצן כלים.
- לוחצים על הלחצן מסוף.
- במסוף, מריצים את הפקודות הבאות כדי לעבור לספרייה
public
ולראות את כל הקבצים שלה:
cd public
ls -lh
גם הגרסה הדחוסה של brotli, main.bundle.js.br
, נשמרת עכשיו כאן וגודלה כ-76% קטן יותר (225KB לעומת 53KB) ביחס ל-main.bundle.js
.
בשלב הבא, צריך להורות לשרת לשלוח את הקבצים האלה שנדחסו ב-brotli בכל פעם שמתקבלת בקשה לגרסאות ה-JS המקוריות שלהם. אפשר לעשות זאת על ידי הגדרת נתיב חדש ב-server.js
לפני שהקבצים מוצגים עם express.static
.
const express = require('express');
const 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()
מוודא שהרצף ממשיך לכל קריאה חוזרת (callback) שתתבצע לאחר מכן.
יכול להיות שחלק מהדפדפנים לא תומכים בדחיסת brotli, לכן חשוב לוודא שיש תמיכה ב-brotli לפני החזרת הקובץ שנדחס באמצעות brotli. לשם כך, בודקים שכותרת הבקשה Accept-Encoding
כוללת את br
:
const express = require('express');
const 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
.