אופטימיזציה של טעינת סקריפטים של צד שלישי ב-Next.js

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

לינה סוהוני
לינה סוהוני
חוסיין דג'ירד
חוסיין דג'ירד

כ-45% מהבקשות מאתרים שמוצגות בניידים ובמחשבים הן בקשות של צד שלישי, שמתוכם 33% הן סקריפטים. הגודל, זמן האחזור והטעינה של סקריפטים של צד שלישי יכולים להשפיע באופן משמעותי על ביצועי האתר. רכיב הסקריפט Next.js כולל שיטות מומלצות מפורטות ומוגדר כברירת מחדל, כדי לעזור למפתחים להציג סקריפטים של צד שלישי באפליקציות שלהם תוך טיפול בבעיות פוטנציאליות בביצועים.

סקריפטים של צד שלישי וההשפעה שלהם על הביצועים

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

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

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

בדיקות של Lighthouse לצמצום משאבים שחוסמים עיבוד וצמצום השימוש בצדדים שלישיים

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

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

  • בממוצע, אתרים משתמשים ב-21 עד 23 צדדים שלישיים שונים – כולל סקריפטים – בניידים ובמחשבים. אופן השימוש וההמלצות עשויים להשתנות עבור כל אחד מהם.
  • ההטמעה של הרבה חברות צד שלישי יכולה להשתנות בהתאם לשימוש ב-framework או בספרייה מסוימת של ממשק המשתמש.
  • ספריות חדשות יותר של צד שלישי מתווספות לעיתים קרובות.
  • דרישות עסקיות שונות הקשורות לאותו צד שלישי מקשות על המפתחים לקבוע סטנדרט אחיד לשימוש במוצר.

ההתמקדות של Aurora בסקריפטים של צד שלישי

כחלק משיתוף הפעולה של Aurora עם הכלים והמסגרות לאינטרנט בקוד פתוח, אנחנו מספקים ברירות מחדל חזקות וכלים מקובעים שיעזרו למפתחים לשפר היבטים שונים בחוויית המשתמש, כמו ביצועים, נגישות, אבטחה ומוכנות לניידים. בשנת 2021 התמקדנו בעזרה למערכים של מסגרת framework לשפר את חוויית המשתמש ואת המדדים של Core Web Vitals

אחד מהשלבים המשמעותיים ביותר להשגת היעד שלנו לשיפור ביצועי ה-framework היה כרוך במחקר לגבי רצף הטעינה האידיאלי של סקריפטים של צד שלישי ב-Next.js. מסגרות כמו Next.js ממוקמות באופן ייחודי כדי לספק ברירות מחדל ותכונות שימושיות שעוזרות למפתחים לטעון משאבים ביעילות, כולל צד שלישי. בדקנו את הנתונים המקיפים של HTTP Archive ו-Lighthouse כדי לגלות אילו פלטפורמות רינדור של צד שלישי פועלות בתדירות הגבוהה ביותר במסגרות שונות.

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

יצירת רצף של סקריפטים של צד שלישי ללא רכיב framework

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

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

       <script src="https://example.com/script1.js" defer></script>
       <script src="https://example.com/script2.js" async></script>
    
  2. יצירת קשרים מוקדמים למקורות נדרשים באמצעות קישור מראש ושליפה מראש של DNS. כך סקריפטים קריטיים יכולים להתחיל להוריד מוקדם יותר.

       <head>
           <link rel="preconnect" href="http://PreconnThis.com">
           <link rel="dns-prefetch" href="http://PrefetchThis.com">
       </head>
    
  3. טעינה מדורגת של משאבים והטמעות של צד שלישי, אחרי שמסתיימת הטעינה של התוכן הראשי בדף או כשהמשתמש גולל למטה עד לחלק בדף שבו הם נכללים.

רכיב הסקריפט Next.js

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

רכיב הסקריפט מבוסס על תג ה-HTML <script> ומאפשר להגדיר את עדיפות הטעינה של סקריפטים של צד שלישי באמצעות מאפיין האסטרטגיה.

// Example for beforeInteractive:
<Script src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserverEntry%2CIntersectionObserver" strategy="beforeInteractive" />

// Example for afterInteractive (default):
<Script src="https://example.com/samplescript.js" />

// Example for lazyonload:
<Script src="https://connect.facebook.net/en_US/sdk.js" strategy="lazyOnload" />

למאפיין האסטרטגיה יכול להיות שלושה ערכים.

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

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

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

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

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

מדידת ההשפעה

השתמשנו בתבניות של אפליקציית המסחר Next.js ושל הבלוג למתחילים כדי ליצור שתי אפליקציות הדגמה (דמו) שעזרו למדוד את ההשפעה של הכללת סקריפטים של צד שלישי. צדדים שלישיים נפוצים עבור הטמעות של Google Tag Manager ומדיה חברתית נכללו בדפים של האפליקציות האלה ישירות קודם ולאחר מכן באמצעות רכיב הסקריפט. לאחר מכן השווינו את הביצועים של הדפים האלה ב-WebPageTest.

סקריפטים של צד שלישי באפליקציית המסחר הבאה.js

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

לפני אחרי
Google Tag Manager עם אסינכרוני רכיב סקריפט עם אסטרטגיה = afterInteractive בשני הסקריפטים
לחצן 'מעקב' ב-Twitter ללא סנכרון או דחייה
הגדרת סקריפט ורכיב סקריפט להדגמה 1 עם 2 סקריפטים.

בהשוואה הבאה אפשר לראות את ההתקדמות החזותית בשתי הגרסאות של Next.js commerce starter-kit. כמו שרואים, LCP מתרחש כמעט שנייה אחת לפני שרכיב הסקריפט מופעל עם אסטרטגיית הטעינה הנכונה.

השוואה של רצועת השקפים שמציגה אלתור ב-LCP

סקריפטים של צד שלישי בבלוג Next.js

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

לפני אחרי
Google Tag Manager עם אסינכרוני רכיב סקריפט עם אסטרטגיה = טעינה עצלנית לכל אחד מארבעת הסקריפטים
לחצן 'מעקב' ב-Twitter עם אסינכרוני
לחצן 'הרשמה למינוי ב-YouTube' ללא אסינכרוניות או דחייה
לחצן 'מעקב' ב-LinkedIn ללא אסינכרוניות או דחייה
הגדרת סקריפט ורכיב סקריפט עבור הדגמה 2 עם 4 סקריפטים.
סרטון שמציג את התקדמות הטעינה של דף האינדקס, עם או בלי רכיב הסקריפט. ה-FCP נכלל בשיפור של 0.5 שניות עם רכיב הסקריפט.

כמו שאפשר לראות בסרטון, הצגת תוכן ראשוני (FCP) מתרחשת ב-0.9 שניות בדף ללא רכיב הסקריפט ו-0.4 שניות ברכיב הסקריפט.

מה השלב הבא ברכיב הסקריפט

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

שימוש ב-Web worker

אפשר להשתמש ב-Web worker כדי להריץ סקריפטים עצמאיים בשרשורי רקע, וכך לפנות את ה-thread הראשי לטיפול במשימות של עיבוד ממשק משתמש ולשפר את הביצועים. רכיבי Web Worker מתאימים במיוחד להסרת עיבוד JavaScript במקום עבודה של ממשק המשתמש, מה-thread הראשי. סקריפטים שמשמשים לתמיכת לקוחות או לשיווק, שבדרך כלל לא מקיימים אינטראקציה עם ממשק המשתמש, עשויים להיות מועמדים טובים להפעלה בשרשור ברקע. ניתן להשתמש בספרייה קלה של צד שלישי – PartyTown – כדי לבודד סקריפטים כאלה ולהפוך אותם ל-Web worker.

בעקבות ההטמעה הנוכחית של רכיב הסקריפט Next.js, מומלץ לדחות את הסקריפטים האלה ב-thread הראשי על ידי הגדרת השיטה ל-afterInteractive או ל-lazyOnload. בעתיד, אנחנו מציעים להוסיף אפשרות אסטרטגית חדשה, 'worker', שתאפשר ל-Next.js להשתמש ב-PartyTown או בפתרון מותאם אישית כדי להריץ סקריפטים בעובדי אינטרנט. נשמח לקבל תגובות ממפתחים בנושא RFC זה.

צמצום למינימום של CLS

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

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

רכיבי ראפ

בדרך כלל תוקנה אסטרטגיית התחביר והטעינה של סקריפטים פופולריים של צד שלישי, כמו Google Analytics או Google Tag Manager (GTM). אפשר להוסיף את ההטמעה הזו ברכיבי wrapper נפרדים לכל סוג של סקריפט. רק קבוצה מינימלית של מאפיינים ספציפיים לאפליקציה (כמו מזהה מעקב) תהיה זמינה למפתחים. רכיבי wrapper יעזרו למפתחים על ידי:

  1. כך יהיה להם קל יותר לכלול תגי סקריפטים פופולריים.
  2. לוודא שה-framework משתמש באסטרטגיה האופטימלית ביותר מאחורי הקלעים.

סיכום

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

אימות חתימות

תודה ל-Kara Erickson, Janicklas Ralph, Katie Hempenius, פיליפ וולטון, ג'רמי וגנר ו-Addy Osmani על המשוב שהם פרסמו.