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

אריק בידלמן

מבוא

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

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

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

קובץ המניפסט של המטמון

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

הפניה לקובץ מניפסט

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

<html manifest="example.appcache">
  ...
</html>

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

כדי לראות את כתובות ה-URL שנשלטות על ידי המטמון של האפליקציה, אפשר להיכנס לכתובת about://appcache-internals/ ב-Chrome. מכאן ניתן לנקות את המטמון ולהציג את הרשומות. יש כלים דומים למפתחים ב-Firefox.

המאפיין manifest יכול להפנות לכתובת URL מוחלטת או לנתיב יחסי, אבל כתובת URL מוחלטת צריכה להיות מאותו מקור כמו אפליקציית האינטרנט. לקובץ מניפסט יכולה להיות כל סיומת, אבל צריך להציג אותו עם סוג ה-MIME הנכון (ראו בהמשך).

<html manifest="http://www.example.com/example.mf">
  ...
</html>

יש לשלוח קובץ מניפסט עם סוג MIME text/cache-manifest. יכול להיות שצריך להוסיף סוג קובץ מותאם אישית לשרת האינטרנט או להגדרות של .htaccess.

לדוגמה, כדי להציג את סוג ה-mime הזה ב-Apache, יש להוסיף את השורה הבאה לקובץ התצורה:

AddType text/cache-manifest .appcache

לחלופין, בקובץ app.yaml ב-Google App Engine:

- url: /mystaticdir/(.*\.appcache)
  static_files: mystaticdir/\1
  mime_type: text/cache-manifest
  upload: mystaticdir/(.*\.appcache)

הדרישה הזו הוסרה מהמפרט לפני זמן מה, והיא כבר לא נדרשת בגרסאות האחרונות של Chrome, Safari ו-Firefox. עם זאת, יהיה צורך בסוג ה-MIME כדי לפעול בדפדפנים ישנים יותר וב-IE11.

המבנה של קובץ מניפסט

המניפסט הוא קובץ נפרד שאליו מקשרים דרך מאפיין המניפסט ברכיב ה-HTML. מניפסט פשוט נראה כך:

CACHE MANIFEST
index.html
stylesheet.css
images/logo.png
scripts/main.js
http://cdn.example.com/scripts/main.js

בדוגמה הזו יישמרו ארבעה קבצים בדף שמציין את קובץ המניפסט הזה.

יש כמה דברים שכדאי לשים לב אליהם:

  • המחרוזת CACHE MANIFEST היא השורה הראשונה וחובה לציין אותה.
  • קבצים יכולים להיות מדומיין אחר
  • חלק מהדפדפנים מגבילים את מכסת האחסון הזמינה לאפליקציה. ב-Chrome, לדוגמה, מטמון האפליקציה משתמש במאגר משותף של נפח אחסון TEMPORARY שממשקי API אחרים אופליין יכולים לשתף. אם ברצונך לכתוב אפליקציה לחנות האינטרנט של Chrome, השימוש ב-unlimitedStorage יסיר את ההגבלה הזו.
  • אם המניפסט עצמו מחזיר 404 או 410, המטמון נמחק.
  • אם ההורדה של המניפסט או המשאב שצוין במניפסט נכשלת, כל תהליך עדכון המטמון ייכשל. במקרה של כשל, הדפדפן ימשיך להשתמש במטמון האפליקציה הישן.

נבחן דוגמה מורכבת יותר:

CACHE MANIFEST
# 2010-06-18:v2

# Explicitly cached 'master entries'.
CACHE:
/favicon.ico
index.html
stylesheet.css
images/logo.png
scripts/main.js

# Resources that require the user to be online.
NETWORK:
*

# static.html will be served if main.py is inaccessible
# offline.jpg will be served in place of all images in images/large/
# offline.html will be served in place of all other .html files
FALLBACK:
/main.py /static.html
images/large/ images/offline.jpg

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

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

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

מניפסט יכול לכלול שלושה קטעים נפרדים: CACHE, NETWORK ו-FALLBACK.

CACHE:
זהו קטע ברירת המחדל לרשומות. קבצים שרשומים מתחת לכותרת הזו (או מיד אחרי ה-CACHE MANIFEST) יישמרו באופן מפורש במטמון אחרי ההורדה הראשונה שלהם. NETWORK:
הקבצים שמופיעים בקטע הזה עשויים להגיע מהרשת אם הם לא שמורים במטמון. אחרת, לא ייעשה שימוש ברשת, גם אם המשתמש מחובר לאינטרנט. אפשר להוסיף כאן כתובות URL ספציפיות לרשימת ההיתרים, או פשוט לכתוב "", כדי להציג את כל כתובות ה-URL. לרוב האתרים צריך את הסימן "". FALLBACK:
קטע אופציונלי שמציין דפים חלופיים אם משאב לא נגיש. ה-URI הראשון הוא המשאב והשני הוא המשאב החלופי שבו נעשה שימוש במקרה שבקשת הרשת נכשלה או שגיאות. שני מזהי ה-URI חייבים להיות מאותו מקור כמו קובץ המניפסט. אפשר לתעד כתובות URL ספציפיות אבל גם קידומות של כתובות URL. הרכיב "images/large/" יתעד כשלים מכתובות URL כגון "images/large/whatever/img.jpg".

המניפסט הבא מגדיר דף "catch-all" (אופליין.html) שיוצג כשהמשתמש ינסה לגשת לשורש של האתר במצב אופליין. בנוסף, מוצהר בו שכל שאר המשאבים (למשל, משאבים באתר מרוחק) דורשים חיבור לאינטרנט.

CACHE MANIFEST
# 2010-06-18:v3

# Explicitly cached entries
index.html
css/style.css

# offline.html will be displayed if the user is offline
FALLBACK:
/ /offline.html

# All other resources (e.g. sites) require the user to be online.
NETWORK:
*

# Additional resources to cache
CACHE:
images/logo1.png
images/logo2.png
images/logo3.png

מתבצע עדכון של המטמון

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

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

סטטוס המטמון

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

var appCache = window.applicationCache;

switch (appCache.status) {
case appCache.UNCACHED: // UNCACHED == 0
return 'UNCACHED';
break;
case appCache.IDLE: // IDLE == 1
return 'IDLE';
break;
case appCache.CHECKING: // CHECKING == 2
return 'CHECKING';
break;
case appCache.DOWNLOADING: // DOWNLOADING == 3
return 'DOWNLOADING';
break;
case appCache.UPDATEREADY:  // UPDATEREADY == 4
return 'UPDATEREADY';
break;
case appCache.OBSOLETE: // OBSOLETE == 5
return 'OBSOLETE';
break;
default:
return 'UKNOWN CACHE STATUS';
break;
};

כדי לבדוק באופן פרוגרמטי אם יש עדכונים למניפסט, קודם צריך לקרוא ל-applicationCache.update(). יתבצע ניסיון לעדכן את המטמון של המשתמש (יש לשנות את קובץ המניפסט). לבסוף, כשה-applicationCache.status נמצא במצב UPDATEREADY, קריאה ל-applicationCache.swapCache() תחליף את המטמון הישן במטמון החדש.

var appCache = window.applicationCache;

appCache.update(); // Attempt to update the user's cache.

...

if (appCache.status == window.applicationCache.UPDATEREADY) {
appCache.swapCache();  // The fetch was successful, swap in the new cache.
}

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

// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {

window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
    // Browser downloaded a new app cache.
    if (confirm('A new version of this site is available. Load it?')) {
    window.location.reload();
    }
} else {
    // Manifest didn't changed. Nothing new to server.
}
}, false);

}, false);

אירועי Appcache

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

function handleCacheEvent(e) {
//...
}

function handleCacheError(e) {
alert('Error: Cache failed to update!');
};

// Fired after the first cache of the manifest.
appCache.addEventListener('cached', handleCacheEvent, false);

// Checking for an update. Always the first event fired in the sequence.
appCache.addEventListener('checking', handleCacheEvent, false);

// An update was found. The browser is fetching resources.
appCache.addEventListener('downloading', handleCacheEvent, false);

// The manifest returns 404 or 410, the download failed,
// or the manifest changed while the download was in progress.
appCache.addEventListener('error', handleCacheError, false);

// Fired after the first download of the manifest.
appCache.addEventListener('noupdate', handleCacheEvent, false);

// Fired if the manifest file returns a 404 or 410.
// This results in the application cache being deleted.
appCache.addEventListener('obsolete', handleCacheEvent, false);

// Fired for each resource listed in the manifest as it is being fetched.
appCache.addEventListener('progress', handleCacheEvent, false);

// Fired when the manifest resources have been newly redownloaded.
appCache.addEventListener('updateready', handleCacheEvent, false);

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

קובצי עזר