טעינה מראש של מודולים

Sérgio Gomes

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

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

<link rel="preload"> הוא דרך לבקש משאבים באופן הצהרתי מראש, לפני שהדפדפן יצטרך אותן.

<head>
  <link rel="preload" as="style" href="critical-styles.css">
  <link rel="preload" as="font" crossorigin type="font/woff2" href="myfont.woff2">
</head>

תמיכה בדפדפן

  • Chrome: 50.
  • קצה: 79 או פחות.
  • Firefox: 85.
  • Safari: 11.1.

מקור

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

<link rel="preload"> והמקבילה שלו לכותרת HTTP מספקים רכיב הצהרתי פשוט דרך להודיע לדפדפן מיד על קבצים קריטיים שנחוצים. כחלק מהניווט הנוכחי. כשהדפדפן מזהה את הטעינה מראש, היא מפעילה בהורדה בעדיפות גבוהה של המשאב, כך שכשהמשאב יהיה מספיק נחוץ, אוחזרו לשם באופן חלקי. עם זאת, היא לא מתאימה למודולים.

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

לתגים <script> ו-<link>, אפשר להגדיר את מצב פרטי הכניסה באמצעות crossorigin . אבל מתברר ש<script type="module"> ללא המאפיין crossorigin מציין מצב של פרטי כניסה של omit, שלא קיים למשך <link rel="preload">. כלומר, צריך לשנות את המאפיין crossorigin גם ב-<script> וגם ב-<link> לאחד של הערכים האחרים, ויכול להיות שלא תהיה לכם דרך קלה לעשות זאת, ניסיון לטעון מראש תלוי במודולים אחרים.

בנוסף, אחזור הקובץ הוא רק השלב הראשון בהפעלת הקוד בפועל. קודם כל, הדפדפן צריך לנתח ולהכיל אותו. במצב אידיאלי, היא צריכה להתרחש גם מראש, כך שכשיש צורך במודול, הקוד מוכן להפעלה. עם זאת, V8 (מנוע ה-JavaScript של Chrome) מנתח ומבצע הידור של מודולים באופן שונה מקוד JavaScript אחר. <link rel="preload"> לא לספק דרך כלשהי לציין שהקובץ שנטען הוא מודול, כך שכל הדפדפן הוא לטעון את הקובץ ולשמור אותו במטמון. לאחר שהסקריפט נטען באמצעות תג <script type="module"> (או שהוא נטען על ידי מודול אחר), הדפדפן מנתח מהקוד צריך להיות מודול JavaScript.

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

<head>
  <link rel="modulepreload" href="super-critical-stuff.mjs">
</head>
[...]
<script type="module" src="super-critical-stuff.mjs">

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

תמיכה בדפדפן

  • Chrome: 66.
  • קצה: 79 או פחות.
  • Firefox: 115.
  • Safari: 17.

מקור

אבל מה לגבי מודולים של יחסי התלות?

מצחיקים שצריך לשאול! יש באמת משהו שלא נכלל במאמר הזה: רקורסיה.

המפרט של <link rel="modulepreload"> מאפשר למעשה טעינה ולא רק את המודול המבוקש, אלא גם את כל עץ התלות שלו. דפדפנים לא חייבים לעשות זאת עושים את זה, אבל הם יכולים.

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

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

<head>
  <!-- dog.js imports dog-head.js, which in turn imports
       dog-head-mouth.js, which imports dog-head-mouth-tongue.js. -->
  <link rel="modulepreload" href="dog-head-mouth-tongue.mjs">
  <link rel="modulepreload" href="dog-head-mouth.mjs">
  <link rel="modulepreload" href="dog-head.mjs">
  <link rel="modulepreload" href="dog.mjs">
</head>

האם טעינה מראש של מודולים עוזרת לשפר את הביצועים?

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

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