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

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

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

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

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

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

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

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

במסמכי התיעוד של WebPageTest מופיעים פרטים על אופן המדידה של התזמונים האלה. במבט חטוף אפשר לראות שכל המדדים האלה של שיעור ה-Lab מושפעים מהמאגר של GTM. לדוגמה, Total Encrypt Time (TBT) – שרת proxy שימושי למעבדה שמבוסס על 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> באמצעות הוספת wrappers ברמה גבוהה יותר שנועדו לפשט את השימוש בתרחישים הנפוצים האלה.

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" />
    </>
  );
}

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

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

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

קובץ GIF שמציג השוואה של טעינת הדפים בין רכיב ההטמעה של YouTube לבין iframe רגיל של YouTube
WebPageTest (Mobile 4G – וירג'יניה ארה"ב)

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

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

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

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

קובץ GIF שמציג הבדלים בזמן החסימה של ה-thread הראשי באסטרטגיות הסקריפט השונות
WebPageTest (Mobile 4G – וירג'יניה ארה"ב)

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

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

השלבים הבאים

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

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

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