في هذه الأيام، تميل المواقع الإلكترونية أو تطبيقات الويب إذا كنت تفضّل ذلك إلى استخدام أحد مخططَي التنقّل:
- توفِّر متصفّحات نظام التنقّل تلقائيًا، أي أنّك تُدخل عنوان URL في شريط عناوين المتصفّح ويعرض طلب التنقّل مستندًا كرد. بعد ذلك، تنقر على رابط يؤدي إلى إلغاء تحميل المستند الحالي إلى رابط آخر، وهو إعلان لا نهائي.
- يشير هذا المصطلح إلى نمط تطبيق من صفحة واحدة يتضمّن طلب تنقّل أوّليًا لتحميل هيكل التطبيق، ويعتمد على JavaScript لتعبئة هيكل التطبيق بترميز يعرضه العميل مع محتوى من واجهة برمجة تطبيقات خلفية لكل عملية "تنقّل".
ذكر المؤيدون لفوائد كل نهج:
- مخطط التنقل الذي توفره المتصفحات بشكل افتراضي مرن، حيث لا تتطلب المسارات الوصول إلى JavaScript. قد يكون أيضًا عرض الترميز عن طريق JavaScript على العميل عملية مكلفة قد تكون مكلفة، ما يعني أنّ الأجهزة ذات المواصفات المنخفضة قد تتأخر في عرض المحتوى بسبب حظر الجهاز لمعالجة النصوص البرمجية التي توفّر المحتوى.
- ومن ناحية أخرى، قد توفر تطبيقات الصفحة الواحدة (SPA) عمليات تنقل أسرع بعد التحميل المبدئي. وبدلاً من الاعتماد على المتصفّح لإلغاء تحميل مستند للحصول على مستند جديد تمامًا (وتكرار ذلك في كل عملية تنقُّل)، يمكن للمطوّرين تقديم تجربة أسرع وأكثر "تشابهًا مع التطبيق". خبرة حتى لو كان ذلك يتطلب عمل JavaScript.
في هذه المشاركة، سنتحدث عن طريقة ثالثة تحقّق توازنًا بين الأسلوبَين الموضّحَين أعلاه، وهما: الاعتماد على عامل الخدمة لتخزين العناصر الشائعة مؤقتًا في الموقع الإلكتروني، مثل ترميز الرأس والتذييل، واستخدام مجموعات البث لتوفير استجابة HTML للعميل في أسرع وقت ممكن، وكل ذلك مع مواصلة استخدام نظام التنقّل التلقائي في المتصفّح.
ما هي أهمية بث ردود HTML في مشغّل الخدمات؟
البث هو إجراء يفعله متصفح الويب بالفعل عند تقديم الطلبات. وهذا مهم للغاية في سياق طلبات التنقّل، لأنّه يضمن عدم حظر المتصفّح في انتظار الرد بالكامل قبل أن يتمكّن من بدء تحليل ترميز المستند وعرض الصفحة.
بالنسبة إلى مشغّلي الخدمات، يختلف البث قليلاً لأنّه يستخدم Streams API بلغة JavaScript. تتمثل أهم المهام التي ينفّذها عامل الخدمة في اعتراض الطلبات والاستجابة لها، بما في ذلك طلبات التنقل.
يمكن أن تتفاعل هذه الطلبات مع ذاكرة التخزين المؤقت بعدة طرق، ولكن نمط التخزين المؤقت الشائع للترميز هو تفضيل استخدام استجابة من الشبكة أولًا، ولكن يتم الرجوع إلى ذاكرة التخزين المؤقت في حال توفّر نسخة قديمة، ويمكنك تقديم استجابة احتياطية عامة إذا لم تكن استجابة قابلة للاستخدام في ذاكرة التخزين المؤقت.
وهذا هو نمط تم اختباره بمرور الوقت للترميز الذي يعمل بشكل جيد، ولكنه يساعد في الموثوقية من حيث الوصول بلا اتصال بالإنترنت، إلا أنه لا يقدم أي مزايا أداء متأصلة لطلبات التنقل التي تعتمد على استراتيجية الشبكة أولاً أو استراتيجية الشبكة فقط. هنا يأتي دور البث وسنستكشف كيفية استخدام وحدة workbox-streams
المستندة إلى Streams API في مشغّل خدمات Workbox، وذلك لتسريع طلبات التنقّل على موقعك الإلكتروني المتعدد الصفحات.
تقسيم صفحة ويب نموذجية
من الناحية الهيكلية، تميل المواقع الإلكترونية إلى تضمين عناصر شائعة في كل صفحة. غالبًا ما يكون الترتيب النموذجي لعناصر الصفحة مشابهًا لما يلي:
- العنوان
- المحتوى.
- التذييل.
وباستخدام web.dev كمثال، يبدو تقسيم العناصر الشائعة هذا على النحو التالي:
إن الهدف من تحديد أجزاء من الصفحة هو أننا نحدد ما يمكن تخزينه مؤقتًا واسترداده دون الانتقال إلى الشبكة - وبالتحديد ترميز الرأس والتذييل المشترك بين جميع الصفحات - وجزء الصفحة الذي ننتقل إليه دائمًا إلى الشبكة أولاً - وهو المحتوى في هذه الحالة.
عندما نعرف كيفية تقسيم أجزاء الصفحة ونحدد العناصر الشائعة، يمكننا كتابة عامل خدمة يسترد دائمًا ترميز الرأس والتذييل على الفور من ذاكرة التخزين المؤقت بينما يطلب المحتوى فقط من الشبكة.
بعد ذلك، باستخدام واجهة برمجة التطبيقات Streams API من خلال workbox-streams
، يمكننا دمج كل هذه الأجزاء معًا والاستجابة لطلبات التنقّل على الفور، مع طلب الحدّ الأدنى من الترميز اللازم من الشبكة.
إنشاء مشغّل خدمة بث
هناك الكثير من العناصر المتغيّرة عندما يتعلق الأمر ببث المحتوى الجزئي في مشغّل الخدمات، ولكن سيتم استكشاف كل خطوة من العملية بالتفصيل مع تقدّمك، بدءًا من كيفية تنظيم بنية موقعك الإلكتروني.
تقسيم موقعك الإلكتروني إلى أجزاء جزئية
قبل البدء في كتابة عامل خدمة البث، عليك تنفيذ ثلاثة إجراءات:
- أنشئ ملفًا يحتوي فقط على ترميز عنوان موقعك الإلكتروني.
- أنشئ ملفًا يحتوي فقط على ترميز تذييل موقعك الإلكتروني.
- اسحب المحتوى الرئيسي لكل صفحة في ملف منفصل، أو اضبط الواجهة الخلفية لعرض محتوى الصفحة بشكل مشروط فقط استنادًا إلى عنوان طلب HTTP.
كما قد تتوقع، فإن الخطوة الأخيرة هي الأصعب، خاصةً إذا كان موقعك الإلكتروني ثابتًا. إذا كان هذا هو الحال بالنسبة إليك، ستحتاج إلى إنشاء نسختين من كل صفحة: ستحتوي النسخة الأولى على ترميز الصفحة الكامل، بينما تحتوي الأخرى على المحتوى فقط.
إنشاء مشغّل خدمة بث
إذا لم تكن قد ثبَّتّ وحدة workbox-streams
، عليك إجراء ذلك بالإضافة إلى أيّ وحدات Workbox مثبّتة حاليًا. بالنسبة لهذا المثال المحدد، يتضمن الحزم التالية:
npm i workbox-navigation-preload workbox-strategies workbox-routing workbox-precaching workbox-streams --save
من هنا، تتمثل الخطوة التالية في إنشاء مشغّل الخدمات الجديد والتخزين المؤقت لأجزاء الرأس والتذييل.
التحضير المسبق الجزئي
عليك أولاً إنشاء مشغّل خدمات في جذر مشروعك باسم 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...
تقوم هذه التعليمات البرمجية بأمرين:
- لتفعيل التحميل المسبق للتنقل في المتصفحات التي تتوافق معه.
- التخزين المؤقت لترميز الرؤوس والتذييلات مسبقًا. وهذا يعني أنه سيتم استرداد ترميز الرأس والتذييل لكل صفحة على الفور، حيث لن يتم حظره من قِبل الشبكة.
- تخزين مواد العرض الثابتة مؤقتًا في العنصر النائب
__WB_MANIFEST
الذي يستخدم الطريقةinjectManifest
عرض الردود تدريجيًا
إنّ أكبر جزء من هذا الجهد هو تكليف عامل الخدمة ببث الردود المجمَّعة. يجعل تطبيق 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.
تتكون هذه التعليمة البرمجية من ثلاثة أجزاء رئيسية تستوفي المتطلبات التالية:
- يتم استخدام استراتيجية
NetworkFirst
للتعامل مع طلبات الحصول على أجزاء من المحتوى. باستخدام هذه الاستراتيجية، يتم تحديد اسمcontent
مخصّص لذاكرة التخزين المؤقت ليحتوي على أجزاء المحتوى، بالإضافة إلى مكوّن إضافي مخصّص يعالج ما إذا كان يجب ضبط عنوان طلبX-Content-Mode
في المتصفّحات التي لا تتيح التحميل المسبق للتنقّل (وبالتالي لا يتم إرسال عنوانService-Worker-Navigation-Preload
). يكتشف هذا المكون الإضافي أيضًا ما إذا كان سيتم إرسال آخر نسخة مخزّنة مؤقتًا من المحتوى جزئيًا، أو إرسال صفحة احتياطية في وضع عدم الاتصال في حالة عدم تخزين نسخة مخزَّنة مؤقتًا للطلب الحالي. - يتم استخدام طريقة
strategy
في اللغةworkbox-streams
(المعروفة أيضًا باسمcomposeStrategies
هنا) لتسلسل أجزاء الرأس والتذييل المخزّنة مسبقًا مع جزء المحتوى المطلوب من الشبكة. - لقد تم تجهيز المخطط بالكامل عبر
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
ترميزًا معيّنًا فقط في الحالات التي يتم استردادها على أنّها جزئية، وسيتم حجب هذا الترميز بعد فترة قصيرة.
الاعتبارات
قبل نشر عامل خدمات لبث البيانات الجزئية ودمجها معًا، هناك بعض الأمور التي يجب مراعاتها. وعلى الرغم من أنّ استخدام مشغّل الخدمات بهذه الطريقة لا يؤدي إلى تغيير جذري في سلوك التنقّل التلقائي في المتصفّح، هناك بعض المشاكل التي قد تحتاج إلى معالجتها.
تعديل عناصر الصفحة عند التنقّل
أصعب جزء من هذا النهج هو أن بعض الأشياء ستحتاج إلى تحديث لدى العميل. على سبيل المثال، يعني ترميز العنوان المسبق أنّ الصفحة ستتضمّن المحتوى نفسه في عنصر <title>
، أو أنّه يجب تعديل حالة إدارة حالة تفعيل/إيقاف عناصر التنقّل في كل عملية تنقُّل. قد يلزم تحديث هذه الأشياء - وغيرها - على العميل لكل طلب تنقل.
لحلّ هذه المشكلة، يمكنك إضافة عنصر <script>
مضمّن إلى جزء من المحتوى مصدره الشبكة، وذلك لتعديل بعض المعلومات المهمة:
<!-- The JSON below contains information about the current page. -->
<script id="page-data" type="application/json">'{"title":"Sand Wasp — 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>
هذا مثال واحد فقط لما قد يتعين عليك فعله إذا قررت بدء إعداد مشغّل الخدمات هذا. بالنسبة إلى التطبيقات الأكثر تعقيدًا التي تتضمن معلومات المستخدم، على سبيل المثال، قد تضطر إلى تخزين وحدات من البيانات ذات الصلة في سوق إلكتروني مثل 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>
توفير رد احتياطي
لنفترض أنك تستخدم استراتيجية تركّز على الشبكة أولاً بشكل جزئي للمحتوى. إذا كان المستخدم غير متصل بالإنترنت وانتقال إلى صفحة سبق أن زارها، سيتم بالتالي حجب هذا المستخدم. ومع ذلك، عند انتقالهم إلى صفحة لم يذهبوا إليها بعد، لن يحصلوا على أي نتائج. ولتجنّب ذلك، عليك عرض استجابة احتياطية.
يتم توضيح التعليمة البرمجية المطلوبة لتحقيق استجابة احتياطية في عيّنات التعليمات البرمجية السابقة. تتطلب هذه العملية خطوتَين:
- تخزين مؤقت لاستجابة احتياطية بلا اتصال بالإنترنت
- يمكنك إعداد رد الاتصال
handlerDidError
في المكوّن الإضافي لإستراتيجيتك التي تعتمد على الشبكة أولاً للتحقق من ذاكرة التخزين المؤقت لآخر إصدار من الصفحة تم الوصول إليه. إذا لم يسبق لك الوصول إلى الصفحة، عليك استخدام الطريقةmatchPrecache
من وحدةworkbox-precaching
لاسترداد الاستجابة الاحتياطية من ذاكرة التخزين المؤقت.
التخزين المؤقت وشبكات توصيل المحتوى (CDN)
إذا كنت تستخدم نمط البث هذا في مشغّل الخدمات، يُرجى تقييم ما إذا كان ينطبق عليك ما يلي:
- يمكنك استخدام شبكة توصيل المحتوى (CDN) أو أي نوع آخر من ذاكرة التخزين المؤقت المتوسطة/العامة.
- لقد حدّدت عنوان
Cache-Control
مع توجيهاتmax-age
و/أوs-maxage
غير صفرية إلى جانب توجيهpublic
.
إذا كان كلا الأمرين كذلك بالنسبة إليك، فقد تحتفظ ذاكرة التخزين المؤقت المتوسطة بالردود لطلبات التنقل. ومع ذلك، تذكر أنه عند استخدام هذا النمط، قد يتم عرض إجابتين مختلفتين لأي عنوان URL محدد:
- الردّ الكامل، الذي يتضمّن ترميز العنوان والمحتوى والتذييل.
- الردّ الجزئي الذي يتضمّن المحتوى فقط
وقد يتسبب ذلك في بعض السلوكيات غير المرغوب فيها، والتي تؤدي إلى مضاعفة ترميز الرأس والتذييل، لأنّ عامل الخدمة قد يجلب استجابة كاملة من ذاكرة التخزين المؤقت لشبكة توصيل المحتوى (CDN) ويدمج ذلك مع ترميز الرأس والتذييل المخزن مؤقتًا بشكل مسبق.
لتفادي ذلك، يجب الاعتماد على عنوان Vary
الذي يؤثر في طريقة التخزين المؤقت من خلال تخزين الردود القابلة للتخزين المؤقت على عنوان واحد أو أكثر من العناوين التي كانت متوفّرة في الطلب. لأنّنا نغيّر الردود على طلبات التنقّل استنادًا إلى عناوين طلبات Service-Worker-Navigation-Preload
وX-Content-Mode
المخصّصة، نحتاج إلى تحديد عنوان Vary
هذا في الردّ:
Vary: Service-Worker-Navigation-Preload,X-Content-Mode
باستخدام هذا العنوان، سيميّز المتصفّح بين الردود الكاملة والجزئية لطلبات التنقّل، مع تجنُّب المشاكل المتعلّقة بترميز الرؤوس والتذييل المزدوجة، كما هو الحال مع أي ذاكرات تخزين مؤقتة وسيطة.
النتيجة
تتلخص معظم نصائح الأداء في وقت التحميل في "عرض ما حصلت عليه" - لا تتردد ولا تنتظر حتى تحصل على كل شيء قبل أن تعرض على المستخدم أي شيء.
"جيك أرشيبالد" في الفيديو Fun Hacks for Faster Content
تتميز المتصفحات بالتميز عندما يتعلق الأمر بالتعامل مع الردود على طلبات التنقل، حتى في النصوص الضخمة لاستجابة HTML. بشكل تلقائي، تعمل المتصفّحات على بث الترميز ومعالجته بشكل تدريجي في مجموعات تتجنّب المهام الطويلة، وهو أمر مفيد لتحسين أداء بدء التشغيل.
يفيدنا ذلك عندما نستخدم نمط مشغّل خدمات البث. عندما تستجيب لطلب من ذاكرة التخزين المؤقت لعامل الخدمة من البداية، تصل بداية الاستجابة على الفور تقريبًا. عند دمج ترميز الرأس والتذييل المخزن مؤقتًا بشكل مسبق مع استجابة من الشبكة، ستحصل على بعض مزايا الأداء الملحوظة:
- غالبًا ما يتم تقليل وقت وصول أول بايت (TTFB) بشكل كبير، لأنّ البايت الأول من الاستجابة لطلب التنقّل يكون فوريًا.
- سيكون سرعة عرض المحتوى على الصفحة (FCP) سريعًا جدًا، لأنّ ترميز العنوان المحفوظ مسبقًا سيحتوي على إشارة إلى ورقة أنماط مخزَّنة مؤقتًا، ما يعني أنّه سيتم عرض محتوى الصفحة بسرعة كبيرة جدًا.
- في بعض الحالات، قد تكون سرعة سرعة عرض أكبر محتوى مرئي (LCP) أسرع أيضًا، لا سيّما إذا تم توفير أكبر عنصر على الشاشة من خلال عنوان النسخة المخزّنة مسبقًا مؤقتًا. ومع ذلك، قد يؤدي مجرد عرض شيء من ذاكرة التخزين المؤقت لمشغِّل الخدمات في أقرب وقت ممكن إلى جانب حمولات الترميز الأصغر إلى تقليل سرعة عرض أكبر جزء من المحتوى على الصفحة.
قد يكون إعداد بث البُنى الأساسية لعدّة صفحات أمرًا صعبًا وتكراره، ولكن التعقيد الذي ينطوي عليه غالبًا ما لا يكون مرهقًا أكثر من SPA من الناحية النظرية. تكمن الميزة الرئيسية في عدم استبدال نظام التنقل التلقائي في المتصفّح، بل سيتم تحسينه.
والأفضل من ذلك، يجعل Workbox هذه البنية ليست ممكنة فقط، ولكنها أسهل مما لو كنت تنفذ ذلك بنفسك. جربه على موقعك الخاص على الويب، ولاحظ مدى سرعة موقعك الإلكتروني متعدد الصفحات للمستخدمين في هذا المجال.