תוספים ל-Chrome: הרחבת ממשק ה-API לתמיכה בניווט מיידי

דייב טפוסקה
דייב טפוסקה

אמ;לק: ממשק ה-API של התוספים עודכן כדי לתמוך במטמון לדף הקודם/הבא, בטעינה מראש של ניווטים. פרטים נוספים מופיעים בהמשך.

ב-Chrome השקענו מאמצים רבים כדי להאיץ את הניווט. טכנולוגיות של ניווט מיידי, כמו מטמון לדף הקודם/הבא (שנשלח למחשב ב-Chrome 96) וכללי ספקולציות (נשלחו ב-Chrome 103) משפרות את החוויה של הניווט אחורה וקדימה. בפוסט הזה נבחן את העדכונים שביצענו בממשקי ה-API של התוספים לדפדפן כדי לתת מענה לתהליכי העבודה החדשים.

הסבר על סוגי הדפים

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

הסרת הדף הפעיל
הסרת הדף הפעיל.

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

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

סוגי דפים
סוגי דפים.

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

מה משתנה מבחינת מפתחי תוספים?

FrameId == 0

ב-Chromium, אנחנו מתייחסים למסגרת העליונה/הראשית כמסגרת החיצונית ביותר.

מחברי תוספים שמניחים שה-frameId של המסגרת החיצונית ביותר הוא 0 (שיטה מומלצת קודמת) עלולים להיתקל בבעיות. מאחר שכרטיסייה יכולה לכלול עכשיו כמה פריימים חיצוניים (דפים שעברו עיבוד מראש ודפים במטמון), ההנחה שיש מסגרת חיצונית אחת לכל כרטיסייה היא שגויה. frameId == 0 עדיין ימשיך לייצג את המסגרת החיצונית של הדף הפעיל, אבל הפריימים החיצוניים של דפים אחרים באותה כרטיסייה לא יהיו אפס. הוספנו שדה חדש מסוג frameType כדי לפתור את הבעיה. עיינו בקטע איך אפשר לקבוע אם מסגרת היא המסגרת החיצונית ביותר? בפוסט הזה.

מחזור חיים של מסגרות לעומת מסמכים

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

אירועי ניווט באינטרנט

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

איך יודעים מהו מחזור החיים של הדף?

הסוג DocumentLifecycle התווסף לכמה ממשקי API של תוספים, שבהם frameId היה זמין בעבר. אם הסוג DocumentLifecycle קיים באירוע (למשל onCommitted), הערך שלו הוא המצב שבו האירוע נוצר. תמיד אפשר להריץ שאילתות לגבי מידע מהשיטות WebNavigation getFrame() ו-getAllFrames(), אבל תמיד עדיף להשתמש בערך מהאירוע. אם תשתמשו בכל אחת מהשיטות, חשוב לשים לב שמצב המסגרת עשוי להשתנות בין המועד שבו האירוע נוצר לבין המועד שבו ההבטחות מוחזרות בשתי השיטות.

השדה DocumentLifecycle כולל את הערכים הבאים:

  • "prerender" : לא מוצג כרגע למשתמש, אך מתכונן לאפשרות שתוצג למשתמש.
  • "active": מוצג כרגע למשתמש.
  • "cached": מאוחסן במטמון לדף הקודם/הבא.
  • "pending_deletion": המסמך מושמד.

איך אני יכול לקבוע אם מסגרת היא המסגרת החיצונית ביותר?

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

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

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

אפשר לשלב את DocumentLifecycle עם FrameType כדי לקבוע אם פריים הוא המסגרת החיצונית הפעילה ביותר. לדוגמה: js tab.documentLifecycle == “active” && frameType == “outermost_frame”

איך פותרים בעיות שקשורות לזמן השימוש במסגרות?

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

כדי לפתור את הבעיה, הצגנו את documentId (ואת parentDocumentId). השיטה webNavigation.getFrame() הופכת עכשיו את frameId לאופציונלית אם מזינים documentId. הערך documentId ישתנה בכל פעם שמנווטים במסגרת.

איך קובעים מתי דף עובר?

קיימים אותות מפורשים שקובעים מתי דף עובר בין מצבים.

בואו נבחן WebNavigation אירועים.

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

onBeforeNavigate
onCommitted
onDOMContentLoaded
onCompleted

ניתן לראות זאת בתרשים הבא, שבו הערך של documentId משתנה ל-"xyz" כשהדף שעבר עיבוד מראש הופך לדף הפעיל.

ה-documentId משתנה כשהדף שעבר עיבוד מראש הופך לדף הפעיל
הdocumentId משתנה כשהדף שעבר עיבוד מראש הופך לדף הפעיל.

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

onBeforeNavigate
onCommitted
onCompleted

האירוע documentId יישאר ללא שינוי כמו באירועים המקוריים. ניתן לראות זאת למעלה כשמתבצעת הפעלה של documentId == xyz. שימו לב שאותה הפעלת אירועי ניווט, מלבד האירוע onDOMContentLoaded, כי הדף כבר נטען.

אם יש לך הערות או שאלות, אתם מוזמנים לשאול בקבוצה chromium-extensions.