אהבת את המטמון ❤️

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

הפוסט הזה הוא כתבה נלווית לסרטון Love your cache, שחלק מהתוכן המורחב בכנס Chrome Dev Summit 2020. מומלץ לצפות בסרטון:

כשמשתמשים יטענו את האתר בפעם השנייה, הדפדפן שלהם ישתמש במשאבים במטמון ה-HTTP שלו כדי לזרז את הטעינה. אבל הסטנדרטים של אחסון במטמון באינטרנט מתוארכים לשנת 1999, והם מוגדרים באופן רחב למדי. לכן, קשה לקבוע אם קובץ, כמו קובץ CSS או תמונה, יובא שוב מהרשת או ייטען מהמטמון.

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

יעדים

כשאתר נטען בפעם השנייה, יש לכם שני יעדים:

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

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

עם זאת, יש גם אמצעי בקרה אחרים שאפשר להשתמש בהם כשמדברים על אחסון במטמון. למשל, יכול להיות שבחרתם לאפשר למטמון ה-HTTP של הדפדפן של המשתמש לשמור את האתר שלכם במשך זמן רב, כדי שלא יידרשו בקשות רשת כדי להציג אותו. לחלופין, אפשר ליצור קובץ שירות (service worker) שיציג אתר באופן אופליין לחלוטין לפני שהוא בודק אם האתר מעודכן. זוהי אפשרות קיצונית, חוקית ומוצלחת בתחומים רבים של חוויית שימוש באינטרנט שמבוססת על אפליקציות אופליין, אבל אין צורך להשתמש באינטרנט רק במצב של אחסון במטמון או רק במצב של שימוש ברשת.

רקע

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

למשתמשים רגילים באינטרנט אין את אותו מותרות. לכן, בנוסף ליעדים המרכזיים שלנו – להבטיח שהמשתמשים ייהנו מהטעינה השנייה – חשוב מאוד גם לוודא שהם לא יהנו פחות או ייתקעו. (כדאי לצפות בסרטון כדי לשמוע איך כמעט גרמנו לאתר web.dev/live להיתקע).

לצורך העניין, אחת הסיבות הנפוצות ל'מטמון לא עדכני' היא למעשה הגדרת ברירת המחדל של שנת 1999 לגבי שמירת נתונים במטמון. הוא מסתמך על הכותרת Last-Modified:

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

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

בעבר זו הייתה כוונה טובה, אבל בגלל האינטגרציה ההדוקה של האתרים של היום, התנהגות ברירת המחדל הזו עלולה לגרום למצב שבו למשתמש יש קבצים שמיועדים לגרסאות שונות של האתר (למשל, קובץ ה-JS מהגרסה שפורסמה ביום שלישי וקובץ ה-CSS מהגרסה שפורסמה ביום שישי), כי הקבצים האלה לא עודכנו באותו זמן.

השביל המואר היטב

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

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

Cache-Control: max-age=0,must-revalidate,public

פירוש הדבר הוא שהקובץ תקף לזמן קצר מאוד, וצריך לאמת אותו מהרשת כדי שתוכלו להשתמש בו שוב (אחרת הוא רק 'מוצע').

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

עם זאת, זוהי גישה מודרנית שהיא ברירת המחדל ב-CDN פופולרי, Netlify, אבל אפשר להגדיר אותה כמעט בכל CDN. ב-Firebase Hosting, אפשר לכלול את הכותרת הזו בקטע האירוח בקובץ firebase.json:

"headers": [
  // Be sure to put this last, to not override other headers
  {
    "source": "**",
    "headers": [ {
      "key": "Cache-Control",
      "value": "max-age=0,must-revalidate,public"
    }
  }
]

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

כתובות URL עם טביעת אצבע

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

Cache-Control: max-age=31536000,immutable

הערך הזה הוא שנה, בשניות. לפי המפרט, זה שווה למעשה ל-"ללא הגבלת זמן".

חשוב לא ליצור את הגיבובים האלה באופן ידני – זו עבודה ידנית רבה מדי. תוכלו להשתמש בכלים כמו Webpack, ‏ Rollup וכו' כדי לעזור לכם בכך. מומלץ לקרוא מידע נוסף עליהם בדוח הכלים.

חשוב לזכור שאפשר להשתמש בחותמות אצבע של כתובות URL לא רק ב-JavaScript, אלא גם בשמות של נכסים כמו סמלים, קובצי CSS וקבצי נתונים אחרים שלא ניתן לשנות. (כדאי גם לצפות בסרטון שלמעלה כדי לקבל מידע נוסף על חלוקת קוד, שמאפשרת לשלוח פחות קוד בכל פעם שמתבצע שינוי באתר).

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

כמובן, אי אפשר לשנות את השם של הדפים 'הידידותיים' שמוצגים למשתמשים בדרך הזו: אי אפשר לשנות את השם של הקובץ index.html ל-index.abcd12.html, כי אי אפשר לבקש מהמשתמשים לעבור לכתובת URL חדשה בכל פעם שהם טוענים את האתר. אי אפשר לשנות את השם של כתובות ה-URL ה'ידידותיות' האלה ולשמור אותן במטמון בדרך הזו, ולכן אני רוצה להציע פתרון ביניים אפשרי.

דרך ביניים

ברור שיש מקום לפשרה כשמדובר בשמירת נתונים במטמון. הצגתי שתי אפשרויות קיצוניות: אף פעם לא לשמור במטמון או תמיד לשמור במטמון. בנוסף, יש כמה קובצי שיכול להיות שתרצו לשמור במטמון לזמן מה, כמו כתובות ה-URL 'הידידותיות' שציינתי למעלה.

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

<img src="/images/foo.jpeg" loading="lazy" />

אם תעדכנו או תשנו את האתר על ידי מחיקה או שינוי של התמונה הזו שנטענת באיטרציה, משתמשים שיציגו גרסה ששמורה במטמון של ה-HTML שלכם עשויים לראות תמונה שגויה או לא לראות תמונה בכלל – כי עדיין נשמרה במטמון הגרסה המקורית של /images/foo.jpeg כשהם נכנסו שוב לאתר.

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

באופן כללי, רוב המדריכים בנושא מטמון מדברים על הגדרות כאלה – האם רוצים לשמור במטמון למשך שעה, כמה שעות וכו'. כדי להגדיר את סוג המטמון הזה, צריך להשתמש בכותרת כזו (שמשמרת במטמון למשך 3600 שניות, שעה אחת):

Cache-Control: max-age=3600,immutable,public

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

אפשרויות שאינן HTML

בנוסף ל-HTML, יש אפשרויות נוספות לקבצים שנמצאים באמצע הדרך:

  • באופן כללי, כדאי לחפש נכסים שלא משפיעים על אחרים

    • לדוגמה: הימנעו משימוש ב-CSS, כי הוא גורם לשינויים באופן שבו ה-HTML מוצג
  • תמונות גדולות שמשולבות במאמרים עדכניים

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

    • יכול להיות שנתוני JSON לגבי מזג האוויר יפורסמו רק כל שעה, כך שאפשר לשמור במטמון את התוצאה הקודמת למשך שעה – היא לא תשתנה בחלון הזמן
    • יכול להיות שיהיו הגבלות קצב על גרסאות build של פרויקטים בקוד פתוח, לכן כדאי לשמור בקובץ מטמון תמונה של סטטוס ה-build עד שיכול להיות שהסטטוס ישתנה

סיכום

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

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

ראה גם

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