عاملو الخدمة ونموذج هيكل التطبيق

من الميزات البنائية الشائعة لتطبيقات الويب من صفحة واحدة (SPA) هي استخدام مجموعة بسيطة من HTML وCSS وJavaScript اللازمة لتشغيل الوظائف العامة لأحد التطبيقات. ومن الناحية العملية، يميل هذا إلى العنوان والتنقل وعناصر واجهة المستخدم الشائعة الأخرى التي تستمر في جميع الصفحات. عندما يخزّن أحد مشغّلي الخدمات محتوى HTML البسيط ومواد العرض التابعة في واجهة المستخدم هذه بشكل مسبق، نُطلق عليه اسم واجهة التطبيق.

رسم تخطيطي لهيكل التطبيق. إنها لقطة شاشة لصفحة ويب تحتوي على عنوان في الأعلى، ومنطقة محتوى في الأسفل. العنوان مسمّى "Application Shell"، بينما يكون الجزء السفلي مصنّفًا على أنّه "Content".

يلعب هيكل التطبيق دورًا مهمًا في الأداء المتصور لتطبيق الويب. وهو أول ما يتم تحميله، وبالتالي فهو أيضًا أول ما يراه المستخدمون أثناء انتظارهم تعبئة المحتوى لواجهة المستخدم.

في حين أن هيكل التطبيق سريع التحميل - بشرط أن تكون الشبكة متاحة وسريعة إلى حد ما - فإن عامل الخدمة الذي يخزّن مسبقًا هيكل التطبيق ومواد العرض المرتبطة به يمنح نموذج هيكل التطبيق هذه المزايا الإضافية:

  • أداء موثوق ومتسق في الزيارات المتكرّرة: عند الزيارة الأولى إلى تطبيق لم يتم تثبيت مشغّل خدمات عليه، يجب تحميل ترميز التطبيق والأصول المرتبطة به من الشبكة قبل أن يتمكن عامل الخدمة من وضعها في ذاكرة التخزين المؤقت. ومع ذلك، فإن الزيارات المتكررة ستسحب هيكل التطبيق من ذاكرة التخزين المؤقت، مما يعني أن التحميل والعرض سيتم بشكل فوري.
  • وصول موثوق إلى الوظائف في حال عدم الاتصال بالإنترنت: أحيانًا يكون الوصول إلى الإنترنت متقطعًا أو غير موجود تمامًا، وتظهر الشاشة المخيفة "لا يمكننا العثور على هذا الموقع" خلفها رأسها. يعالج نموذج هيكل التطبيق هذه المشكلة عن طريق الاستجابة لأي طلب تنقل باستخدام ترميز هيكل التطبيق من ذاكرة التخزين المؤقت. حتى إذا زار شخص عنوان URL في تطبيق الويب لم يذهب إليه من قبل، سيتم عرض هيكل التطبيق من ذاكرة التخزين المؤقت، ويمكن ملؤه بمحتوى مفيد.

متى يجب استخدام نموذج هيكل التطبيق

تكون هيكل التطبيق أكثر منطقية عندما يكون لديك عناصر واجهة مستخدم شائعة لا تتغير من مسار إلى آخر، لكن المحتوى يتغير. ومن المرجح أن تستخدم معظم التطبيقات الترويجية بشكل فعال نموذج هيكل التطبيق بالفعل.

إذا كان هذا يصف مشروعك، وتريد إضافة عامل خدمات لتعزيز موثوقيته وأدائه، فإن هيكل التطبيق يجب أن:

  • تحميل سريع:
  • استخدِم مواد عرض ثابتة من مثيل Cache.
  • تضمين عناصر واجهة شائعة مثل العنوان والشريط الجانبي، منفصلة عن محتوى الصفحة.
  • استرداد المحتوى الخاص بالصفحة وعرضه.
  • يمكنك تخزين المحتوى الديناميكي مؤقتًا إذا كان ذلك مناسبًا لمشاهدته بلا اتصال بالإنترنت.

يُحمِّل هيكل التطبيق المحتوى الخاص بالصفحة ديناميكيًا من خلال واجهات برمجة التطبيقات أو المحتوى الذي تم تجميعه بلغة JavaScript. كما يجب أن يكون تحديثًا ذاتيًا، بمعنى أنه في حالة تغيير ترميز هيكل التطبيق، يجب أن يلتقط تحديث مشغّل الخدمات هيكل التطبيق الجديد ويخزِّنه في ذاكرة التخزين المؤقت تلقائيًا.

إنشاء هيكل التطبيق

يجب أن يكون هيكل التطبيق مستقلاً عن المحتوى، ومع ذلك يوفر قاعدة لتعبئة المحتوى بداخله. من الناحية المثالية، يجب أن يكون الهاتف نحيفًا قدر الإمكان، مع تضمين محتوى كافٍ ومفيد في التنزيل الأوليّ ليفهم المستخدم أنّ التجربة يتم تحميلها بسرعة.

يعتمد التوازن الصحيح على تطبيقك. يتضمّن هيكل التطبيق في Trained To Thrill التابع لـ "جيك أرشيبالد" عنوانًا يحتوي على زر إعادة تحميل لسحب محتوى جديد من Flutter.

لقطة شاشة لتطبيق الويب Trained to Thrill في حالتين مختلفتين على يمين الصفحة، لا يظهر سوى هيكل التطبيق المُخزَّن مؤقتًا، بدون تعبئة أي محتوى. على يسار الصفحة، يتم تحميل المحتوى (بعض الصور لبعض القطارات) ديناميكيًا في منطقة محتوى هيكل التطبيق.

سيختلف ترميز هيكل التطبيق من مشروع إلى آخر، ولكن إليك مثالاً على ملف index.html الذي يوفر النموذج النموذجي للتطبيق:

​​<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>
      Application Shell Example
    </title>
    <link rel="manifest" href="/manifest.json">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="stylesheet" type="text/css" href="styles/global.css">
  </head>
  <body>
    <header class="header">
      <!-- Application header -->
      <h1 class="header__title">Application Shell Example</h1>
    </header>

    <nav class="nav">
      <!-- Navigation items -->
    </nav>

    <main id="app">
      <!-- Where the application content populates -->
    </main>

    <div class="loader">
      <!-- Spinner/content placeholders -->
    </div>

    <!-- Critical application shell logic -->
    <script src="app.js"></script>

    <!-- Service worker registration script -->
    <script>
      if ('serviceWorker' in navigator) {
        // Register a service worker after the load event
        window.addEventListener('load', () => {
          navigator.serviceWorker.register('/sw.js');
        });
      }
    </script>
  </body>
</html>

كيفما تنشئ هيكل تطبيق لمشروعك، يجب أن تكون له الخصائص التالية:

  • يجب أن يحتوي HTML على مناطق معزولة بوضوح لعناصر واجهة المستخدم الفردية. في المثال أعلاه، يتضمن ذلك رأس التطبيق، والتنقل، ومنطقة المحتوى الرئيسية، ومساحة "الأداة الدوارة" للتحميل التي تظهر فقط عند تحميل المحتوى.
  • يجب أن تكون قيمة JavaScript وCSS التي يتم تحميلها في هيكل التطبيق ضئيلة جدًا، وأن ترتبط فقط بوظيفة هيكل التطبيق نفسه وليس بالمحتوى. ويضمن ذلك عرض التطبيق للواجهة في أسرع وقت ممكن، ويقلل من عمل سلسلة التعليمات الرئيسية إلى أن يظهر المحتوى.
  • نص برمجي مضمّن يسجّل مشغّل الخدمات.

وبعد إنشاء هيكل التطبيق، يمكنك إنشاء عامل خدمات لتخزين كل من هيكله وأصوله مؤقتًا.

تخزين هيكل التطبيق في ذاكرة التخزين المؤقت

هيكل التطبيق وأصوله المطلوبة هما ما يجب أن يخزّنه عامل الخدمة بشكل مسبق فور التثبيت. على افتراض أن هيكل التطبيق مثل المثال أعلاه، فلنرى كيف يمكن للمرء تحقيق ذلك في مثال أساسي لـ Workbox باستخدام workbox-build:

// build-sw.js
import {generateSW} from 'workbox-build';

// Where the generated service worker will be written to:
const swDest = './dist/sw.js';

generateSW({
  swDest,
  globDirectory: './dist',
  globPatterns: [
    // The necessary CSS and JS for the app shell
    '**/*.js',
    '**/*.css',
    // The app shell itself
    'shell.html'
  ],
  // All navigations for URLs not precached will use this HTML
  navigateFallback: 'shell.html'
}).then(({count, size}) => {
  console.log(`Generated ${swDest}, which precaches ${count} assets totaling ${size} bytes.`);
});

إنّ هذه الإعدادات المخزّنة في build-sw.js تستورد لغة CSS وJavaScript الخاصة بالتطبيق، بما في ذلك ملف ترميز واجهة برمجة التطبيقات المضمَّنة في shell.html. يتم تنفيذ النص البرمجي باستخدام Node مثل ذلك:

node build-sw.js

تتم كتابة مشغّل الخدمات الذي تم إنشاؤه إلى "./dist/sw.js"، وسيسجِّل الرسالة التالية عند الانتهاء:

Generated ./dist/sw.js, which precaches 5 assets totaling 44375 bytes.

عند تحميل الصفحة، يخزّن مشغّل الخدمات ذاكرة التخزين المؤقت لترميز واجهة أوامر التطبيق وتبعياته:

لقطة شاشة للوحة الشبكة في &quot;أدوات مطوّري البرامج في Chrome&quot; تعرض قائمة بمواد العرض التي تم تنزيلها من الشبكة يتم تمييز مواد العرض التي خزّنها مشغّل الخدمات في ذاكرة التخزين المؤقت مسبقًا عن مواد العرض الأخرى التي يظهر رمز ترس على يسار الصف. يخزّن مشغّل الخدمات بشكل مسبق العديد من ملفات JavaScript وCSS أثناء التثبيت.
يحتفظ مشغّل الخدمات بذاكرة التخزين المؤقت لتبعيات واجهة أوامر التطبيق عند التثبيت. تمثّل طلبات التخزين المؤقت آخر صفَّين، ويشير رمز الترس بجانب الطلب إلى أنّ عامل الخدمة قد عالج الطلب.

يمكن إجراء تخزين مؤقت لملفات HTML وCSS وJavaScript على هيكل تطبيقك في أي سير عمل تقريبًا، بما في ذلك المشاريع التي تستخدم برامج التجميع. أثناء تقدُّمك في المستندات، ستتعلّم طريقة استخدام Workbox مباشرةً لإعداد سلسلة أدواتك لإنشاء عامل خدمات يناسب مشروعك بشكل أفضل، بغض النظر عمّا إذا كان SPA.

الخاتمة

إنّ الجمع بين نموذج هيكل التطبيق ومشغّل الخدمات هو أمر رائع للتخزين المؤقت بلا اتصال بالإنترنت، خاصةً إذا كنت قد دمجت وظيفة التخزين المؤقت السابقة مع استراتيجية الشبكة أولاً، والعودة إلى ذاكرة التخزين المؤقت للترميز أو استجابات واجهة برمجة التطبيقات. وتكون النتيجة تجربة سريعة وموثوقة تعرض التطبيق بشكل فوري عند تكرار الزيارات، حتى في حالة عدم الاتصال بالإنترنت.