אפליקציות מהירות יותר למספר דפים עם זרמי נתונים

כיום, אתרים – או אפליקציות אינטרנט – נוטים להשתמש באחת משתי סכימות ניווט:

  • הדפדפנים של סכימת הניווט מספקים כברירת מחדל. כלומר, מזינים כתובת URL בסרגל הכתובות של הדפדפן ובקשת ניווט מחזירה מסמך כתגובה. לאחר מכן לוחצים על קישור, שמסיר את המסמך ad infinitum מהמסמך הנוכחי.
  • דפוס האפליקציה של דף יחיד, שכרוך בבקשת ניווט ראשונית כדי לטעון את מעטפת האפליקציה. הדפוס הזה מסתמך על JavaScript כדי לאכלס את מעטפת האפליקציה בתגי עיצוב שמעובדים על ידי הלקוח בתוכן מ-API לקצה העורפי לכל 'ניווט'.

היתרונות של כל גישה הוצגו על ידי תומכים:

  • סכימת הניווט שדפדפנים מספקים כברירת מחדל היא עמידה, מאחר שאין צורך לגשת ל-JavaScript בנתיבים. עיבוד על ידי לקוח של תגי עיצוב באמצעות JavaScript יכול גם להיות תהליך יקר שעשוי להיות יקר. כלומר, מכשירים מתקדמים יותר עלולים להגיע למצב שבו התוכן מתעכב, מאחר שהמכשיר נחסם לצורך עיבוד סקריפטים שמספקים תוכן.
  • מצד שני, אפליקציות של דף יחיד (SPA) עשויות לספק ניווט מהיר יותר לאחר הטעינה הראשונית. במקום להסתמך על כך שהדפדפן יפרוש מסמך כדי ליצור מסמך חדש לגמרי (ויחזור על כך בכל ניווט), הוא יכול להציע חוויה מהירה 'דומה יותר לאפליקציה' – אפילו אם הפעולה הזו מחייבת JavaScript.

בפוסט הזה נדבר על שיטה שלישית שיוצרת איזון בין שתי הגישות שתוארו למעלה: הסתמכות על Service Worker כדי לשמור מראש את הרכיבים הנפוצים של אתר — כמו תגי עיצוב של כותרות עליונות ותחתונות – ושימוש בזרמים כדי לספק תגובת HTML ללקוח במהירות רבה ככל האפשר, תוך שימוש בסכימת הניווט המוגדרת כברירת מחדל של הדפדפן.

למה כדאי לשדר תגובות HTML ב-Service Worker?

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

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

עבור קובצי שירות (service worker), הסטרימינג מעט שונה מפני שהוא משתמש ב-Streams API של JavaScript. המשימה החשובה ביותר ש-Service Worker ממלא היא ליירט בקשות ולהגיב להן – כולל בקשות ניווט.

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

זהו תבנית שנבדקה במשך הזמן עבור תגי עיצוב ופועלת היטב, אבל למרות שהיא עוזרת באמינות של גישה במצב אופליין, היא לא מציעה יתרונות ביצועים מהותיים לבקשות ניווט המסתמכות על אסטרטגיה תחילה לרשת או רשת בלבד. כאן סטרימינג מגיע, ונראה איך להשתמש במודול workbox-streams המופעל על ידי Streams API ב-Workbox Service Worker כדי להאיץ בקשות ניווט באתר מרובה דפים.

פירוט של דף אינטרנט רגיל

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

  • כותרת.
  • תוכן.
  • כותרת תחתונה.

אם נשתמש ב-web.dev כדוגמה, הפירוט של הרכיבים הנפוצים נראה כך:

פירוט של הרכיבים הנפוצים באתר web.dev. האזורים המשותפים המתוארים מסומנים ב 'כותרת', 'תוכן' ו 'כותרת תחתונה'.

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

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

לאחר מכן, באמצעות ממשק ה-API של Streams דרך workbox-streams, נוכל לחבר את כל החלקים האלה יחד ולהגיב לבקשות ניווט באופן מיידי – תוך כדי בקשה לכמות המינימלית של תגי עיצוב שנדרשת מהרשת.

בניית קובץ שירות סטרימינג (service worker)

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

פילוח האתר לחלקים

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

  1. יצירת קובץ שמכיל רק את תגי העיצוב של כותרת האתר.
  2. יצירת קובץ שמכיל רק את תגי העיצוב של הכותרת התחתונה באתר.
  3. עליך למשוך את התוכן הראשי של כל דף לקובץ נפרד או להגדיר את הקצה העורפי כך שיציג רק את תוכן הדף לפי תנאי על סמך כותרת של בקשת HTTP.

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

חיבור קובץ שירות סטרימינג

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

npm i workbox-navigation-preload workbox-strategies workbox-routing workbox-precaching workbox-streams --save

מכאן השלב הבא הוא יצירת קובץ השירות (service worker) החדש שלך ושמירת החלקים של הכותרת העליונה והתחתונה במטמון.

טעינה מראש של חלקים מסוימים במטמון

הדבר הראשון שצריך לעשות הוא ליצור קובץ שירות (service worker) בשורש של הפרויקט בשם sw.js (או כל שם קובץ אחר המועדף). הכותרת מתחילה בדברים הבאים:

// sw.js
import * as navigationPreload from 'workbox-navigation-preload';
import {NetworkFirst} from 'workbox-strategies';
import {registerRoute} from 'workbox-routing';
import {matchPrecache, precacheAndRoute} from 'workbox-precaching';
import {strategy as composeStrategies} from 'workbox-streams';

// Enable navigation preload for supporting browsers
navigationPreload.enable();

// Precache partials and some static assets
// using the InjectManifest method.
precacheAndRoute([
  // The header partial:
  {
    url: '/partial-header.php',
    revision: __PARTIAL_HEADER_HASH__
  },
  // The footer partial:
  {
    url: '/partial-footer.php',
    revision: __PARTIAL_FOOTER_HASH__
  },
  // The offline fallback:
  {
    url: '/offline.php',
    revision: __OFFLINE_FALLBACK_HASH__
  },
  ...self.__WB_MANIFEST
]);

// To be continued...

הקוד הזה מבצע שתי פעולות:

  1. מפעיל טעינה מראש של ניווט עבור דפדפנים שתומכים באפשרות הזו.
  2. שומר מראש את תגי העיצוב של הכותרת העליונה והתחתונה. פירוש הדבר הוא שסימון הכותרת העליונה והתחתונה של כל דף יאוחזר באופן מיידי, מאחר שהרשת לא תחסום אותו.
  3. שומר מראש נכסים סטטיים ב-placeholder של __WB_MANIFEST שמשתמש בשיטה injectManifest.

הצגת התשובות באופן שוטף

החלק הכי חשוב בתהליך הזה הוא לגרום ל-Service Worker להזרים תגובות משורשרות. למרות זאת, ה-Workbox וה-workbox-streams שלו הופכים את האירוע הזה לתמציתי הרבה יותר מאשר אם הייתם צריכים לעשות את כל זה בעצמכם:

// sw.js
import * as navigationPreload from 'workbox-navigation-preload';
import {NetworkFirst} from 'workbox-strategies';
import {registerRoute} from 'workbox-routing';
import {matchPrecache, precacheAndRoute} from 'workbox-precaching';
import {strategy as composeStrategies} from 'workbox-streams';

// ...
// Prior navigation preload and precaching code omitted...
// ...

// The strategy for retrieving content partials from the network:
const contentStrategy = new NetworkFirst({
  cacheName: 'content',
  plugins: [
    {
      // NOTE: This callback will never be run if navigation
      // preload is not supported, because the navigation
      // request is dispatched while the service worker is
      // booting up. This callback will only run if navigation
      // preload is _not_ supported.
      requestWillFetch: ({request}) => {
        const headers = new Headers();

        // If the browser doesn't support navigation preload, we need to
        // send a custom `X-Content-Mode` header for the back end to use
        // instead of the `Service-Worker-Navigation-Preload` header.
        headers.append('X-Content-Mode', 'partial');

        // Send the request with the new headers.
        // Note: if you're using a static site generator to generate
        // both full pages and content partials rather than a back end
        // (as this example assumes), you'll need to point to a new URL.
        return new Request(request.url, {
          method: 'GET',
          headers
        });
      },
      // What to do if the request fails.
      handlerDidError: async ({request}) => {
        return await matchPrecache('/offline.php');
      }
    }
  ]
});

// Concatenates precached partials with the content partial
// obtained from the network (or its fallback response).
const navigationHandler = composeStrategies([
  // Get the precached header markup.
  () => matchPrecache('/partial-header.php'),
  // Get the content partial from the network.
  ({event}) => contentStrategy.handle(event),
  // Get the precached footer markup.
  () => matchPrecache('/partial-footer.php')
]);

// Register the streaming route for all navigation requests.
registerRoute(({request}) => request.mode === 'navigate', navigationHandler);

// Your service worker can end here, or you can add more
// logic to suit your needs, such as runtime caching, etc.

קוד זה מורכב משלושה חלקים עיקריים שעומדים בדרישות הבאות:

  1. אסטרטגיית NetworkFirst משמשת לטיפול בבקשות לחלקים מהתוכן. בשיטה הזו, מצוין שם מטמון מותאם אישית של content שמכיל את חלקי התוכן, וגם פלאגין מותאם אישית שמטפל אם להגדיר כותרת בקשה של X-Content-Mode עבור דפדפנים שלא תומכים בטעינה מראש של ניווט (ולכן לא שולחים כותרת Service-Worker-Navigation-Preload). הפלאגין הזה גם יודע אם לשלוח את הגרסה האחרונה שנשמרה במטמון של התוכן החלקי, או לשלוח דף חלופי במצב אופליין אם לא שמורה גרסה שנשמרה במטמון של הבקשה הנוכחית.
  2. השיטה strategy ב-workbox-streams (מופיעה כאן כ-composeStrategies) משמשת לשרשור החלקיים של הכותרת העליונה והתחתונה השמורים במטמון יחד עם התוכן החלקי המבוקש מהרשת.
  3. כל התוכנית מאומתת באמצעות registerRoute בבקשות ניווט.

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

אם לאתר שלכם יש קצה עורפי

חשוב לזכור שכאשר מופעלת טעינה מראש של ניווט, הדפדפן שולח כותרת Service-Worker-Navigation-Preload עם הערך true. עם זאת, בדוגמת הקוד שלמעלה, שלחנו כותרת מותאמת אישית של X-Content-Mode כשטעינה מראש של ניווט באירוע לא נתמכת בדפדפן. בקצה העורפי, הייתם משנים את התגובה בהתאם לנוכחות של הכותרות האלה. בקצה עורפי של PHP, זה עשוי להיראות בערך כך לדף נתון:

<?php
// Check if we need to render a content partial
$navPreloadSupported = isset($_SERVER['HTTP_SERVICE_WORKER_NAVIGATION_PRELOAD']) && $_SERVER['HTTP_SERVICE_WORKER_NAVIGATION_PRELOAD'] === 'true';
$partialContentMode = isset($_SERVER['HTTP_X_CONTENT_MODE']) && $_SERVER['HTTP_X_CONTENT_MODE'] === 'partial';
$isPartial = $navPreloadSupported || $partialContentMode;

// Figure out whether to render the header
if ($isPartial === false) {
  // Get the header include
  require_once($_SERVER['DOCUMENT_ROOT'] . '/includes/site-header.php');

  // Render the header
  siteHeader();
}

// Get the content include
require_once('./content.php');

// Render the content
content($isPartial);

// Figure out whether to render the footer
if ($isPartial === false) {
  // Get the footer include
  require_once($_SERVER['DOCUMENT_ROOT'] . '/includes/site-footer.php');

  // Render the footer
  siteFooter();
}
?>

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

שיקולים

לפני שאתם פורסים קובץ שירות (service worker) כדי לשדר ולתפור חלקים מסוימים יחד, יש כמה דברים שצריך לקחת בחשבון. זה נכון שהשימוש ב-Service Worker בדרך הזו לא משנה באופן מהותי את התנהגות ברירת המחדל של הדפדפן לניווט, אבל יש כמה דברים שסביר להניח שתצטרכו לטפל בהם.

עדכון רכיבים בדף במהלך הניווט

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

כדי לעקוף את הבעיה, תוכלו להציב רכיב <script> מוטבע בחלק התוכן שמגיע מהרשת, כדי לעדכן כמה נתונים חשובים:

<!-- The JSON below contains information about the current page. -->
<script id="page-data" type="application/json">'{"title":"Sand Wasp &mdash; World of Wasps","description":"Read all about the sand wasp in this tidy little post."}'</script>
<script>
  const pageData = JSON.parse(document.getElementById('page-data').textContent);

  // Update the page title
  document.title = pageData.title;
</script>
<article>
  <!-- Page content omitted... -->
</article>

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

טיפול ברשתות איטיות

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

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

אחת הדרכים לעשות זאת היא באמצעות שירות CSS. נניח שהכותרת החלקית מסתיימת ברכיב <article> פותח שהוא ריק עד שהתוכן החלקי מגיע כדי לאכלס אותו. אפשר לכתוב כלל CSS דומה לזה:

article:empty::before {
  text-align: center;
  content: 'Loading...';
}

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

.slow article:empty::before {
  text-align: center;
  content: 'Loading...';
}

מכאן אפשר להשתמש ב-JavaScript בכותרת באופן חלקי כדי לקרוא את סוג החיבור האפקטיבי (לפחות בדפדפני Chromium) כדי להוסיף את המחלקה slow לרכיב <html> בסוגי חיבור נבחרים:

<script>
  const effectiveType = navigator?.connection?.effectiveType;

  if (effectiveType !== '4g') {
    document.documentElement.classList.add('slow');
  }
</script>

פעולה זו תבטיח שסוגי חיבורים יעילים איטיים יותר מסוג 4g יקבלו הודעת טעינה. לאחר מכן, בחלק של התוכן, תוכלו להציב רכיב <script> בתוך השורה כדי להסיר את המחלקה slow מה-HTML וכך להיפטר מהודעת הטעינה:

<script>
  document.documentElement.classList.remove('slow');
</script>

מתן תגובת גיבוי

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

הקוד הדרוש כדי להשיג תגובת גיבוי מודגם בדגימות קוד קודמות. התהליך כולל שני שלבים:

  1. שמירה מראש של תגובה חלופית במצב אופליין.
  2. מגדירים קריאה חוזרת (callback) של handlerDidError בפלאגין לאסטרטגיה עם עדיפות לרשת כדי לבדוק את המטמון של גרסת הדף האחרונה שניגשה אליה. אם מעולם לא בוצעה גישה לדף, תצטרכו להשתמש ב-method matchPrecache מהמודול workbox-precaching כדי לאחזר את תגובת החלופה מהמטמון מראש.

שמירה במטמון ו-CDN

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

  • אתם משתמשים ב-CDN או בכל סוג אחר של מטמון ביניים/ציבורי.
  • ציינת כותרת Cache-Control עם הוראות max-age ו/או s-maxage שאינן אפס בשילוב עם ההוראה public.

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

  • התשובה המלאה, שכוללת את תגי העיצוב של הכותרת העליונה, התוכן והכותרת התחתונה.
  • התשובה החלקית, שמכילה רק את התוכן.

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

כדי לעקוף את הבעיה, צריך להסתמך על הכותרת Vary, שמשפיעה על התנהגות השמירה במטמון על ידי הוספת תגובות שניתן לשמור במטמון לכותרת אחת או יותר שנכללו בבקשה. אנחנו משנים את התגובות לבקשות הניווט בהתאם לכותרות של הבקשות מסוג Service-Worker-Navigation-Preload ובקשות X-Content-Mode מותאמות אישית, לכן אנחנו צריכים לציין בתגובה את הכותרת הבאה מסוג Vary:

Vary: Service-Worker-Navigation-Preload,X-Content-Mode

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

התוצאה

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

ג'ייק ארצ'יבלד ב-Fun Hacks for Faster Content

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

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

  • לעיתים קרובות, זמן עד בייט ראשון (TTFB) יצטמצם מאוד, מאחר שהבייט הראשון של התגובה לבקשת ניווט מתבצע באופן מיידי.
  • הצגת תוכן ראשוני (FCP) תהיה מהירה מאוד, כי תגי העיצוב של הכותרת שנשמרים מראש במטמון יכילו הפניה לגיליון סגנונות שנשמר במטמון. כלומר, הדף יצויר מהר מאוד.
  • במקרים מסוימים, גם התכונה Largest Contentful Paint (LCP) יכולה להיות מהירה יותר, במיוחד אם הרכיב הגדול ביותר במסך מסופק על ידי החלק העליון של הכותרת שנשמרה במטמון מראש. עם זאת, הצגת משהו מתוך המטמון של קובץ השירות (service worker) בהקדם האפשרי לצד מטענים ייעודיים (payloads) קטנים יותר של תגי עיצוב, עשויה להוביל ל-LCP טוב יותר.

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

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

מקורות מידע