איך מאיצים את האפליקציה שלכם ב-Next.js באמצעות פיצול קוד ואסטרטגיות טעינה חכמות.
פורסם: 8 בנובמבר 2019
מידע על סוגים שונים של פיצול קוד ואיך להשתמש בייבוא דינמי כדי להאיץ את האפליקציות שלכם ב-Next.js.
פיצול קוד מבוסס-נתיב ופיצול קוד מבוסס-רכיב
כברירת מחדל, Next.js מפצלת את קובץ ה-JavaScript לחלקים נפרדים לכל מסלול. כשמשתמשים טוענים את האפליקציה, Next.js שולח רק את הקוד שדרוש לנתיב הראשוני. כשמשתמשים עוברים בין חלקים שונים באפליקציה, הם מאחזרים את החלקים שמשויכים לנתיבים האחרים. פיצול קוד מבוסס-מסלול מצמצם את כמות הסקריפט שצריך לנתח ולבצע קומפילציה בבת אחת, וכך מקצר את זמני הטעינה של הדפים.
פיצול קוד לפי נתיב הוא ברירת מחדל טובה, אבל אפשר לשפר עוד יותר את תהליך הטעינה באמצעות פיצול קוד ברמת הרכיב. אם יש לכם רכיבים גדולים באפליקציה, מומלץ לפצל אותם לחלקים נפרדים. כך אפשר לבצע טעינה עצלה של רכיבים גדולים שלא חיוניים או שמוצגים רק באינטראקציות מסוימות של המשתמשים (כמו לחיצה על לחצן).
Next.js תומך בדינמיות import(), שמאפשרת לייבא מודולים של JavaScript (כולל רכיבי React) באופן דינמי ולטעון כל ייבוא כחלק נפרד. כך מתבצע פיצול קוד ברמת הרכיב, ואתם יכולים לשלוט בטעינת המשאבים כדי שהמשתמשים יורידו רק את הקוד שהם צריכים לחלק באתר שהם צופים בו. ב-Next.js, רכיבים כאלה עוברים רינדור בצד השרת (SSR) כברירת מחדל.
ייבוא דינמי בפעולה
הפוסט הזה כולל כמה גרסאות של אפליקציה לדוגמה שמורכבת מדף פשוט עם כפתור אחד. כשלוחצים על הכפתור, רואים גור חמוד. בכל גרסה של האפליקציה תוכלו לראות את ההבדלים בין ייבוא דינמי לבין ייבוא סטטי, ואיך עובדים עם ייבוא דינמי.
בגרסה הראשונה של האפליקציה, הגור גר בcomponents/Puppy.js. כדי להציג את הגור בדף, האפליקציה מייבאת את רכיב Puppy ב-index.js באמצעות הצהרת ייבוא סטטית:
import Puppy from "../components/Puppy";
כדי לראות איך Next.js מאגד את האפליקציה, בודקים את המעקב אחר הרשת בכלי הפיתוח:
כדי לראות תצוגה מקדימה של האתר, לוחצים על הצגת האפליקציה ואז על מסך מלא
.
מקישים על Control+Shift+J (או על Command+Option+J ב-Mac) כדי לפתוח את כלי הפיתוח.
לוחצים על הכרטיסייה רשת.
מסמנים את תיבת הסימון השבתת המטמון.
טוענים מחדש את הדף.
כשמטעינים את הדף, כל הקוד הנדרש, כולל הרכיב Puppy.js
, נארז ב-index.js:
כשלוחצים על הלחצן Click me, רק הבקשה לתמונת הגור בפורמט JPEG מתווספת לכרטיסייה Network:
החיסרון בגישה הזו הוא שגם אם המשתמשים לא לוחצים על הלחצן כדי לראות את הגור, הם צריכים לטעון את הרכיב Puppy כי הוא כלול ב-index.js. בדוגמה הקטנה הזו זה לא משנה, אבל ביישומים בעולם האמיתי, לרוב מדובר בשיפור משמעותי לטעון רכיבים גדולים רק כשצריך.
עכשיו נבדוק גרסה שנייה של האפליקציה, שבה הייבוא הסטטי מוחלף בייבוא דינמי. Next.js כולל את next/dynamic, שמאפשר להשתמש בייבוא דינמי של כל רכיב ב-Next:
import Puppy from "../components/Puppy";
import dynamic from "next/dynamic";
// ...
const Puppy = dynamic(import("../components/Puppy"));
פועלים לפי השלבים בדוגמה הראשונה כדי לבדוק את מעקב הרשת.
בפעם הראשונה שאתם טוענים את האפליקציה, רק index.js מורד. הפעם הוא קטן ב-0.5 KB (הוא ירד מ-37.9 KB ל-37.4 KB) כי הוא לא כולל את הקוד של הרכיב Puppy:
הרכיב Puppy נמצא עכשיו בחלק נפרד, 1.js, שנטען רק כשלוחצים על הכפתור:
ביישומים בעולם האמיתי, הרכיבים הם לרוב הרבה יותר גדולים, וטעינה עצלה שלהם יכולה לצמצם את מטען ה-JavaScript הראשוני במאות קילובייט.
ייבוא דינמי עם אינדיקטור טעינה בהתאמה אישית
כשמבצעים טעינה עצלה של משאבים, מומלץ לספק אינדיקטור טעינה למקרה שיהיו עיכובים. ב-Next.js, אפשר לעשות את זה על ידי הוספת ארגומנט לפונקציה dynamic():
const Puppy = dynamic(() => import("../components/Puppy"), {
loading: () => <p>Loading...</p>
});
כדי לראות את אינדיקטור הטעינה בפעולה, מדמים חיבור רשת איטי ב-DevTools:
כדי לראות תצוגה מקדימה של האתר, לוחצים על הצגת האפליקציה ואז על מסך מלא
.
מקישים על Control+Shift+J (או על Command+Option+J ב-Mac) כדי לפתוח את כלי הפיתוח.
לוחצים על הכרטיסייה רשת.
מסמנים את תיבת הסימון השבתת המטמון.
ברשימה הנפתחת ויסות נתונים (throttle), בוחרים באפשרות 3G מהיר.
לוחצים על הלחצן Click me (לחצו עליי).
עכשיו, כשלוחצים על הלחצן, לוקח זמן לטעון את הרכיב והאפליקציה, ובזמן הזה מוצגת ההודעה 'טעינה…'.
ייבוא דינמי ללא SSR
אם אתם צריכים לעבד רכיב רק בצד הלקוח (לדוגמה, ווידג'ט של צ'אט), אתם יכולים לעשות זאת על ידי הגדרת האפשרות ssr לערך false:
const Puppy = dynamic(() => import("../components/Puppy"), {
ssr: false,
});
סיכום
עם תמיכה בייבוא דינמי, Next.js מאפשר פיצול קוד ברמת הרכיב, מה שיכול לצמצם את מטעני ה-JavaScript ולשפר את זמן הטעינה של האפליקציה. כברירת מחדל, כל הרכיבים עוברים עיבוד בצד השרת, ואפשר להשבית את האפשרות הזו בכל שלב.