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

ה-Codelab הזה בוחן איך גם למזער וגם לדחוס את JavaScript עבור האפליקציה הבאה משפרת את ביצועי הדפים על ידי הפחתת גודל הבקשה של האפליקציה.

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

מדידה

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

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

לאפליקציה הזו, שדווח גם במאמר "הסרת פריטים שאינם בשימוש" codelab", מאפשר לך להצביע עבור הפריט המועדף עליך חתלתול. 🐈

עכשיו, נבחן את גודל האפליקציה:

  1. מקישים על 'Control+Shift+J' (או על 'Command+Option+J' ב-Mac) כדי לפתוח את כלי הפיתוח.
  2. לוחצים על הכרטיסייה רשתות.
  3. מסמנים את התיבה Disable cache (השבתת מטמון).
  4. טוענים מחדש את האפליקציה.

גודל החבילה המקורי בחלונית 'רשת'

למרות שכבר התבצעה התקדמות רבה בקטע "הסרת קוד שאינו בשימוש". Codelab כדי להקטין את גודל החבילה, 225KB הוא עדיין די גדול.

הקטנה

נבחן את בלוק הקוד הבא.

function soNice() {
  let counter = 0;

  while (counter < 100) {
    console.log('nice');
    counter++;
  }
}

אם הפונקציה הזו שמורה בקובץ משלה, גודל הקובץ הוא בערך 112B (בייטים).

אם מסירים את כל הרווחים הלבנים, הקוד שמתקבל ייראה כך:

function soNice(){let counter=0;while(counter<100){console.log("nice");counter++;}}

גודל הקובץ עכשיו יהיה כ-83B. אם הוא נפגע עוד יותר על ידי הפחתת את האורך של שם המשתנה ומשנה כמה ביטויים, הקוד הסופי עשוי בסוף ייראה כך:

function soNice(){for(let i=0;i<100;)console.log("nice"),i++}

גודל הקובץ מגיע עכשיו ל-B62.

בכל שלב קשה יותר לקרוא את הקוד. עם זאת, בחלק של הדפדפן המנוע של JavaScript מפרש כל אחד מהמאפיינים האלה בדיוק באותו אופן. היתרון של ערפול קוד באופן הזה יכול לעזור בהשגת קובץ קטן יותר בגדלים שונים. 112 B ממש לא היה הרבה בהתחלה, אבל עדיין היה 50% וגודלה ירד!

באפליקציה הזו, webpack בגרסה 4 משמש Bundler של מודולים. ניתן לראות את הגרסה הספציפית ב-package.json.

"devDependencies": {
  //...
  "webpack": "^4.16.4",
  //...
}

גרסה 4 כבר מקטינה את החבילה כברירת מחדל במהלך מצב הייצור. הוא משתמש TerserWebpackPlugin פלאגין עבור Terser. Terser הוא כלי פופולרי לדחיסת קוד JavaScript.

כדי לקבל מושג איך נראה הקוד המוקטן, צריך ללחוץ על main.bundle.js כשגולשים בחלונית רשת של כלי פיתוח. עכשיו לוחצים על בכרטיסייה תגובה.

תגובה ממוזערת

הקוד בצורתו הסופית, מוקטן ופגום, מוצג בגוף התגובה. כדי לבדוק מה היה גודל החבילה אם היא לא הייתה מוקטנת, פותחים את webpack.config.js ולעדכן את ההגדרות האישיות של mode.

module.exports = {
  mode: 'production',
  mode: 'none',
  //...

טוענים מחדש את האפליקציה ובודקים שוב את גודל החבילה דרך החלונית רשת של כלי פיתוח

גודל החבילה: 767KB

זה הבדל גדול למדי! 😅

לפני שממשיכים, צריך לבטל את השינויים כאן.

module.exports = {
  mode: 'production',
  mode: 'none',
  //...

הכללת תהליך להקטנת קוד באפליקציה תלויה בכלים שבהם משתמשים:

  • אם משתמשים ב-webpack מגרסה 4 ואילך, אין צורך לבצע פעולות נוספות כי הקוד מוקטן כברירת מחדל במצב ייצור. 👍
  • אם משתמשים בגרסה ישנה יותר של Webpack, צריך להתקין ולכלול את TerserWebpackPlugin לתהליך ה-build של ה-webpack. מסמכי התיעוד מוסבר על זה בפירוט.
  • קיימים גם יישומי פלאגין אחרים להקטנה ואפשר להשתמש בהם במקומם, כמו BabelMinifyWebpackPlugin ו-ClosureCompilerPlugin.
  • אם לא נעשה שימוש ב-מודול Bundler בכלל, צריך להשתמש ב-Terser ככלי CLI או לכלול אותו ישירות כתלות.

דחיסה

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

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

כל בקשת ותגובה של HTTP, דפדפנים ושרתי אינטרנט יכולים להוסיף headers להכללה מידע נוסף על הנכס שמאוחזר או מתקבל. סוג הפריט יכול להיות מופיע בכרטיסייה Headers בחלונית 'רשת כלי הפיתוח', שבה יש שלושה סוגים מוצגות:

  • General (כללי) מייצג כותרות כלליות שרלוונטיות לכל הבקשה-תגובה אינטראקציה חוזרת.
  • בכותרות של תגובה מוצגות רשימה של כותרות שספציפיות לתגובה עצמה. מהשרת.
  • בכותרות של בקשות מוצגת רשימה של כותרות שמצורפים לבקשה על ידי הלקוח.

כדאי לקרוא את הכותרת accept-encoding ב-Request Headers.

אישור כותרת הקידוד

הדפדפן משתמש ב-accept-encoding כדי לציין את התוכן או באלגוריתמים לדחיסה, שהוא תומך בהם. יש הרבה יש אלגוריתמים לדחיסת טקסט, אבל יש רק שלושה נתמכת כאן לצורך דחיסה (וביטול דחיסה) של בקשות רשת HTTP:

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

האפליקציה לדוגמה במדריך הזה זהה לאפליקציה שהושלמה Codelab "Remove unused code" (הסרת קוד שאינו בשימוש), למעט העובדה Express משמש עכשיו כ-framework של שרת. ב במספר קטעים, הוא נבחן גם דחיסה סטטית וגם דינמית.

דחיסה דינמית

דחיסה דינמית כוללת דחיסת נכסים בזמן אמת כל עוד הם מקבלים שהופעל על ידי הדפדפן.

יתרונות

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

חסרונות

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

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

כדי לוודא שכל הנכסים יידחסו בכל פעם שהבקשה נשלחת, דחיסה של ספריית תווכה . כדי להתחיל, צריך להוסיף אותו בתור devDependency ב-package.json:

"devDependencies": {
  //...
  "compression": "^1.7.3"
},

ומייבאים אותו לקובץ השרת, server.js:

const express = require('express');
const compression = require('compression');

ומוסיפים אותה כתווכה לפני הטעינה של express.static:

//...

const app = express();

app.use(compression());

app.use(express.static('public'));

//...

עכשיו צריך לטעון מחדש את האפליקציה ולבדוק את גודל החבילה בחלונית רשת.

גודל החבילה עם דחיסה דינמית

מ-225KB עד 61.6KB! בResponse Headers עכשיו, content-encoding הכותרת מציינת שהשרת שולח למטה את הקובץ הזה עם קידוד של gzip.

כותרת קידוד תוכן

דחיסה סטטית

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

יתרונות

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

חסרונות

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

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

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

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

"devDependencies": {
  //...
  "compression-webpack-plugin": "^1.1.11"
},

כמו כל פלאגין אחר של Webpack, מייבאים אותו בקובץ התצורות, webpack.config.js:

const path = require("path");

//...

const CompressionPlugin = require("compression-webpack-plugin");

ונכלול אותו במערך plugins:

module.exports = {
  //...
  plugins: [
    //...
    new CompressionPlugin()
  ]
}

כברירת מחדל, הפלאגין דוחס את קובצי ה-build באמצעות gzip. העף מבט במסמכי התיעוד ללמוד איך להוסיף אפשרויות לשימוש באלגוריתם אחר או לכלול או להחריג קבצים מסוימים.

כשהאפליקציה נטענת מחדש ונבנית מחדש, גרסה דחוסה של החבילה הראשית נוצר. פותחים את Glitch Console כדי לראות מה יש בתוך ספריית public/ הסופית שמוצגת על ידי שרת ה-Node.

  • לוחצים על הלחצן כלים.
  • לוחצים על הלחצן Console.
  • במסוף, מריצים את הפקודות הבאות כדי לשנות אותן אל public ולראות את כל הקבצים שלה:
cd public
ls

הקבצים שהפלט האחרון התקבל בספרייה הציבורית

גרסת gzip של החבילה, main.bundle.js.gz, שמורה עכשיו כאן כ- נו. CompressionPlugin גם מכווצת את index.html כברירת מחדל.

הדבר הבא שיש לעשות הוא לומר לשרת לשלוח קבצים דחוסים מסוג gzip קבצים בכל פעם שנשלחה בקשה לגרסאות ה-JS המקוריות שלהם. אפשר לעשות את זה על ידי הגדרת נתיב חדש ב-server.js לפני שהקבצים מוצגים express.static.

const express = require('express');
const app = express();

app.get('*.js', (req, res, next) => {
  req.url = req.url + '.gz';
  res.set('Content-Encoding', 'gzip');
  next();
});

app.use(express.static('public'));

//...

app.get משמש כדי להורות לשרת איך להגיב לבקשת GET נקודת קצה ספציפית. המערכת משתמשת בפונקציית קריאה חוזרת כדי להגדיר איך לטפל בבעיה בקשה. המסלול פועל כך:

  • אם מציינים את '*.js' כארגומנט הראשון, הפעולה הזאת פועלת בכל נקודת הקצה (endpoint) שמופעלת כדי לאחזר קובץ JS.
  • בקריאה החוזרת, .gz מצורף לכתובת ה-URL של הבקשה, כותרת התשובה Content-Encoding מוגדרת לgzip.
  • לבסוף, next() מבטיח שהרצף ימשיך בכל קריאה חוזרת שעשויים להיות בשלב הבא.

אחרי שהאפליקציה נטענת מחדש, בודקים שוב את החלונית Network.

צמצום גודל החבילה באמצעות דחיסה סטטית

בדיוק כמו קודם, הופחתה ירידה משמעותית בגודל החבילה!

סיכום

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