חבילת Next.js לניהול ספריות של צד שלישי

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

בפוסט הזה בבלוג נספק סקירה כללית של התכונות החדשות שהשקנו, במיוחד הספרייה @next/third-parties, וכן סקירה כללית של יוזמות עתידיות במפת הדרכים שלנו.

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

41% מכל הבקשות של צד שלישי באתרי Next.js הן סקריפטים. בניגוד לסוגי תוכן אחרים, הורדה והפעלה של סקריפטים יכולות להימשך זמן רב, וכתוצאה מכך יכול להיות עיכוב ברינדור ובאינטראקציה של המשתמשים. נתונים מדוח חוויית המשתמש ב-Chrome‏ (CrUX) מראים שבאתרים של Next.js שמטעינים יותר סקריפטים של צד שלישי, שיעורי הצלחה של מהירות התגובה לאינטראקציה באתר (INP) ושל המהירות שבה נטען רכיב התוכן הכי גדול (LCP) נמוכים יותר.

תרשים עמודות שבו מוצג ירידה באחוז הנכסים ב-Next.js שהשיגו ציונים טובים במדדי INP ו-LCP, בהתאם למספר הצדדים השלישיים שנטענו
דוח CrUX מדצמבר 2023 (110,823 אתרים)

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

תרשים עמודות שבו מוצג ההבדל בין מדדים שונים של מעבדה כשאתר נטען עם Google Tag Manager וללא Google Tag Manager
WebPageTest (Mobile 4G - Virginia USA)

בתיעוד של WebPageTest מוסבר איך נמדדים הזמנים האלה. במבט מהיר, ברור שכל מדדי המעבדה האלה מושפעים מהקונטיינר של GTM. לדוגמה, בשירות Total Blocked Time (TBT) – שרת proxy שימושי ל-Lab שמודד את INP – הייתה עלייה של כמעט פי 20.

רכיב סקריפט

כשהשקנו את הרכיב <Script> ב-Next.js, הקפדנו להציג אותו באמצעות ממשק API ידידותי למשתמש שדומה מאוד לאלמנט <script> המסורתי. בעזרת היכולת הזו, מפתחים יכולים למקם סקריפט של צד שלישי בכל רכיב באפליקציה, ו-Next.js ידאג לסדר את הסקריפט אחרי טעינת המשאבים הקריטיים.

<!-- By default, script will load after page becomes interactive -->
<Script src="https://example.com/sample.js" />

<!-- Script is injected server-side and fetched before any page hydration occurs -->
<Script strategy=”beforeInteractive” src="https://example.com/sample.js" />

<!-- Script is fetched later during browser idle time -->
<Script strategy=”lazyOnload” src="https://example.com/sample.js" />

עשרות אלפי אפליקציות Next.js – כולל אתרים פופולריים כמו Patreon,‏ Target ו-Notion – משתמשות ברכיב <Script>. למרות היעילות שלו, חלק מהמפתחים הביעו חששות לגבי הנושאים הבאים:

  • איפה למקם את הרכיב <Script> באפליקציית Next.js תוך שמירה על ההוראות השונות להתקנה של ספקי צד שלישי שונים (חוויית המפתח).
  • אסטרטגיית הטעינה האופטימלית ביותר לשימוש בסקריפטים שונים של צד שלישי (חוויית משתמש).

כדי לטפל בשני החששות האלה, השקנו את @next/third-parties – ספרייה ייעודית שמציעה קבוצה של רכיבים ושירותים מנוהלים שמותאמים לצדדים שלישיים פופולריים.

חוויית המפתח: ניהול קל יותר של ספריות של צד שלישי

בחלק גדול מהאתרים ב-Next.js נעשה שימוש בסקריפטים רבים של צד שלישי, כאשר Google Tag Manager הוא הפופולרי ביותר, ו66% מהאתרים משתמשים בו. ה-@next/third-parties פועל על הרכיב <Script> בכך שהוא כולל רכיבי wrapper ברמה גבוהה יותר שנועדו לפשט את השימוש בתרחישים נפוצים האלה.

import { GoogleAnalytics } from "@next/third-parties/google";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
      <GoogleTagManager gtmId="GTM-XYZ" />
    </html>
  );
}

גם ל-Google Analytics – סקריפט נוסף של צד שלישי שנמצא בשימוש נרחב (52% מהאתרים ב-Next.js) – יש רכיב ייעודי משלו.

import { GoogleAnalytics } from "@next/third-parties/google";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
      <GoogleAnalytics gaId="G-XYZ" />
    </html>
  );
}

@next/third-parties מפשט את תהליך הטעינה של סקריפטים נפוצים, אבל הוא גם מרחיב את היכולת שלנו לפתח כלי עזר לקטגוריות אחרות של צדדים שלישיים, כמו הטמעות. לדוגמה, בהטמעות של מפות Google ו-YouTube נעשה שימוש ב-8% וב-4% מהאתרים של Next.js בהתאמה, ושלחנו גם רכיבים כדי להקל על הטעינה שלהם.

import { GoogleMapsEmbed } from "@next/third-parties/google";
import { YouTubeEmbed } from "@next/third-parties/google";

export default function Page() {
  return (
    <>
      <GoogleMapsEmbed
        apiKey="XYZ"
        height={200}
        width="100%"
        mode="place"
        q="Brooklyn+Bridge,New+York,NY"
      />
      <YouTubeEmbed videoid="ogfYd705cRs" height={400} params="controls=0" />
    </>
  );
}

חוויית משתמש: טעינה מהירה יותר של ספריות של צד שלישי

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

לדוגמה, תוכלו להטמיע סרטונים מ-YouTube. במקרים שבהם יש הטמעות חלופיות עם ביצועים טובים בהרבה מההטמעה המובנית. נכון לעכשיו, הרכיב <YouTubeEmbed> שיוצא על ידי @next/third-parties משתמש ב-lite-youtube-embed, שמטען מהר יותר בהשוואה ל-"Hello, World" ב-Next.js.

קובץ GIF שבו מוצגת השוואה בין זמן הטעינה של דף עם רכיב ההטמעה של YouTube לבין זמן הטעינה של דף עם iframe רגיל של YouTube
WebPageTest (Mobile 4G - Virginia USA)

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

הפעלת סקריפטים של צד שלישי ב-Web Worker

אחת מהשיטות המתקדמות שאנחנו בודקים ב-@next/third-parties היא הפחתת העומס על הסקריפטים של הצד השלישי באמצעות משימות ברקע באינטרנט. השיטה הזו, שפופולרית בספריות כמו Partytown, יכולה להפחית באופן משמעותי את ההשפעה של סקריפטים של צד שלישי על ביצועי הדף, על ידי העברה שלהם לגמרי מהשרשור הראשי.

בקובץ ה-GIF הבא מוצגים השינויים במשך הזמן של משימות ארוכות ובזמן החסימה של הליבה כשמחילים אסטרטגיות שונות של <Script> על מאגר GTM באתר Next.js. חשוב לזכור שהחלפת האפשרויות של האסטרטגיה רק מעכבת את מועד ההפעלה של הסקריפטים האלה, אבל העברה שלהם ל-web worker מבטלת לחלוטין את הזמן שהם נמצאים בו בשרשור הראשי.

קובץ GIF שמציג הבדלים בזמן החסימה של השרשורים העיקריים בשיטות השונות של הסקריפטים
WebPageTest (Mobile 4G - Virginia USA)

בדוגמה הספציפית הזו, העברת הביצוע של מאגר התגים ב-GTM והסקריפטים של התגים המשויכים אליו ל-web worker צמצמה את זמן הטעינה של הדף ב-92%.

חשוב לציין שאם לא תנהלו את השיטה הזו בצורה קפדנית, היא עלולה לגרום להצגה שקטה של סקריפטים רבים של צד שלישי, דבר שמקשה על ניפוי הבאגים. בחודשים הקרובים נבדוק אם רכיבי צד שלישי שמוצעים על ידי @next/third-parties פועלים בצורה תקינה כשהם מופעלים ב-web worker. אם כן, נעבוד על מתן דרך קלה ואופציונלית למפתחים להשתמש בשיטה הזו.

השלבים הבאים

בתהליך הפיתוח של החבילה הזו, התברר שיש צורך לרכז את ההמלצות בנוגע לטעינת צד שלישי, כדי שגם מסגרות אחרות יוכלו ליהנות מאותן שיטות בסיסיות. לכן פיתחנו את Third Party Capital, ספרייה שמשתמשת ב-JSON כדי לתאר שיטות טעינה של צד שלישי, וכיום היא משמשת כבסיס ל-@next/third-parties.

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

אם אחד מהשירותים של הצד השלישי שבהם אתם משתמשים באפליקציית Next.js נתמך על ידי @next/third-parties, תוכלו להתקין את החבילה ולנסות אותה. נשמח לקבל ממך משוב ב-GitHub.