โปรแกรมทำงานของบริการและโมเดล Shell ของแอปพลิเคชัน

ฟีเจอร์ทางสถาปัตยกรรมที่พบบ่อยของเว็บแอปพลิเคชันในหน้าเดียว (SPA) คือชุด HTML, CSS และ JavaScript ขั้นต่ำที่จำเป็นในการขับเคลื่อนฟังก์ชันส่วนกลางของแอปพลิเคชัน ในทางปฏิบัติ นี่มักจะเป็นส่วนหัว การนำทาง และองค์ประกอบอินเทอร์เฟซผู้ใช้ทั่วไปอื่นๆ ที่คงอยู่ในทุกหน้า เมื่อ Service Worker แคช HTML ขั้นต่ำและเนื้อหาที่เกี่ยวข้องของ UI นี้ไว้ล่วงหน้า เราเรียกการดำเนินการนี้ว่า Application Shell

แผนภาพของ Application Shell ซึ่งเป็นภาพหน้าจอของหน้าเว็บที่มีส่วนหัวที่ด้านบนและพื้นที่เนื้อหาที่ด้านล่าง ส่วนหัวจะมีป้ายกำกับว่า "Application Shell" แต่ด้านล่างจะมีป้ายกำกับเป็น "Content"

Application Shell มีบทบาทสำคัญในประสิทธิภาพที่รับรู้ของเว็บแอปพลิเคชัน โฆษณานี้เป็นสิ่งแรกที่โหลด ดังนั้นจึงเป็นสิ่งแรกที่ผู้ใช้เห็นขณะที่รอให้เนื้อหาปรากฏในอินเทอร์เฟซผู้ใช้

แม้ว่า Application Shell นั้นจะโหลดได้เร็ว แต่ในกรณีที่เครือข่ายพร้อมใช้งานและค่อนข้างเร็ว โปรแกรมทำงานของบริการที่แคช App Shell และเนื้อหาที่เกี่ยวข้องไว้ล่วงหน้าจะทำให้โมเดล Application Shell ได้รับประโยชน์ดังนี้

  • ประสิทธิภาพที่มั่นคงและเชื่อถือได้ในการกลับมาอยู่เสมอ ในครั้งแรกที่เข้าชมแอปโดยไม่ได้ติดตั้ง Service Worker ไว้ มาร์กอัปของแอปพลิเคชันและเนื้อหาที่เกี่ยวข้องจะต้องโหลดจากเครือข่ายก่อน โปรแกรมทำงานของบริการจึงจะนำมาร์กอัปดังกล่าวไปไว้ในแคชได้ อย่างไรก็ตาม การเข้าชมซ้ำจะดึง Application Shell จากแคช ซึ่งหมายความว่าการโหลดและการแสดงผลจะเกิดขึ้นทันที
  • เข้าถึงฟังก์ชันการทำงานที่เชื่อถือได้ในสถานการณ์ออฟไลน์ บางครั้งการเข้าถึงอินเทอร์เน็ตขาดหายเป็นช่วงๆ หรือไม่มีอยู่เลย และหน้าจอ "เราไม่พบเว็บไซต์นั้น" ที่น่ากลัว โมเดล Shell ของแอปพลิเคชันจะจัดการเรื่องนี้โดยตอบกลับคำขอการนำทางด้วยมาร์กอัป Application Shell จากแคช แม้ว่าจะมีผู้เข้าชม URL ในเว็บแอปซึ่งไม่เคยไปมาก่อน ระบบจะแสดง Application Shell จากแคชและเติมเนื้อหาที่เป็นประโยชน์ได้

กรณีที่ควรใช้โมเดล Application Shell

Application Shell มีประโยชน์ที่สุดเมื่อคุณมีองค์ประกอบอินเทอร์เฟซผู้ใช้ทั่วไปที่ไม่เปลี่ยนจากเส้นทางหนึ่งไปยังเส้นทาง แต่เนื้อหาเปลี่ยน SPA ส่วนใหญ่มีแนวโน้มที่จะใช้โมเดล Shell ของแอปพลิเคชันที่มีประสิทธิภาพอยู่แล้ว

หากคำอธิบายนี้อธิบายถึงโปรเจ็กต์ของคุณและคุณต้องการเพิ่ม Service Worker เพื่อปรับปรุงความน่าเชื่อถือและประสิทธิภาพ เชลล์ของแอปพลิเคชันควรดำเนินการดังนี้

  • โหลดเร็ว
  • ใช้ชิ้นงานแบบคงที่จากอินสแตนซ์ Cache
  • มีองค์ประกอบอินเทอร์เฟซทั่วไป เช่น ส่วนหัวและแถบด้านข้าง โดยแยกจากเนื้อหาของหน้าเว็บ
  • ดึงและแสดงเนื้อหาเฉพาะหน้าเว็บ
  • หากเหมาะสม คุณสามารถเลือกแคชเนื้อหาแบบไดนามิกสำหรับการดูแบบออฟไลน์ได้

Application Shell จะโหลดเนื้อหาเฉพาะหน้าเว็บแบบไดนามิกผ่าน API หรือเนื้อหาที่รวมอยู่ใน JavaScript นอกจากนี้ยังควรอัปเดตด้วยตนเองในกรณีที่หากมาร์กอัปของ Application Shell มีการเปลี่ยนแปลง การอัปเดต Service Worker ควรจะรับ Application Shell ใหม่และแคชโดยอัตโนมัติ

การสร้าง Application Shell

Application Shell ควรอยู่แยกต่างหากจากเนื้อหา แต่จัดเตรียมฐานสำหรับการเติมข้อมูลภายในเนื้อหา ตามหลักแล้วควรจะมีขนาดเล็กที่สุดเท่าที่จะทำได้ แต่รวมเนื้อหาที่มีความหมายมากพอในการดาวน์โหลดครั้งแรกที่ผู้ใช้เข้าใจว่าประสบการณ์โหลดได้อย่างรวดเร็ว

ความสมดุลที่เหมาะสมขึ้นอยู่กับแอปของคุณ เช่น Application Shell สำหรับแอปTrained To Thrill ของ Jake Archibald มีส่วนหัวที่มีปุ่มรีเฟรชเพื่อดึงเนื้อหาใหม่จาก Flickr

ภาพหน้าจอของเว็บแอป Trained to Thrill ใน 2 สถานะ ทางด้านซ้าย คุณจะเห็นเพียง Shell ของแอปพลิเคชันที่แคชไว้เท่านั้น โดยไม่มีการสร้างเนื้อหา ทางด้านขวา เนื้อหา (ภาพบางส่วนของรถไฟบางขบวน) จะโหลดแบบไดนามิกในพื้นที่เนื้อหาของ Application Shell

มาร์กอัป Application Shell จะแตกต่างกันไปในแต่ละโปรเจ็กต์ แต่ต่อไปนี้คือตัวอย่างหนึ่งของไฟล์ 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>

ไม่ว่าคุณจะสร้าง Application Shell สำหรับโปรเจ็กต์ของคุณ โปรเจ็กต์จะต้องมีลักษณะดังต่อไปนี้

  • HTML ควรมีพื้นที่ที่แยกไว้อย่างชัดเจนสำหรับองค์ประกอบอินเทอร์เฟซผู้ใช้แต่ละรายการ ในตัวอย่างข้างต้น ซึ่งรวมถึงส่วนหัว การนำทาง พื้นที่เนื้อหาหลัก และพื้นที่สำหรับ "ตัวหมุน" การโหลดที่จะปรากฏขึ้นเฉพาะเมื่อเนื้อหากำลังโหลดเท่านั้น
  • JavaScript และ CSS แรกที่โหลดสำหรับ Application Shell ควรมีจำนวนน้อยที่สุด และเกี่ยวข้องกับฟังก์ชันการทำงานของ Application Shell เท่านั้น ไม่ใช่ตัวเนื้อหา วิธีนี้ทำให้แอปพลิเคชันแสดงผล Shell โดยเร็วที่สุด และลดปริมาณงานเทรดหลักจนกว่าเนื้อหาจะปรากฏ
  • สคริปต์ในหน้าที่ลงทะเบียน Service Worker

เมื่อสร้าง Application Shell แล้ว คุณจะสร้าง Service Worker เพื่อแคชทั้ง App Shell และเนื้อหาได้

การแคช Application Shell

Application Shell และเนื้อหาที่จำเป็นคือสิ่งที่ Service Worker ควรแคชล่วงหน้าทันทีที่ติดตั้ง สมมติว่า Application Shell เป็นเหมือนตัวอย่างด้านบน มาลองดูกันว่า App Shell จะทำเช่นนี้ได้อย่างไรในตัวอย่าง 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 ของแอป รวมถึงไฟล์มาร์กอัป Application Shell ที่อยู่ใน shell.html สคริปต์จะดำเนินการโดยใช้โหนด ดังนี้

node build-sw.js

ระบบจะเขียน Service Worker ที่สร้างขึ้นไปยัง ./dist/sw.js และจะบันทึกข้อความต่อไปนี้เมื่อเสร็จสิ้น

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

เมื่อหน้าเว็บโหลด โปรแกรมทำงานของบริการจะแคชมาร์กอัป Application Shell และการอ้างอิงไว้ล่วงหน้าไว้ล่วงหน้า ดังนี้

ภาพหน้าจอของแผงเครือข่ายในเครื่องมือสำหรับนักพัฒนาเว็บของ Chrome ซึ่งแสดงรายการเนื้อหาที่ดาวน์โหลดจากเครือข่าย ชิ้นงานที่ Service Worker แคชล่วงหน้าจะแตกต่างจากชิ้นงานอื่นๆ ที่มีเฟืองทางซ้ายในแถว ไฟล์ JavaScript และ CSS หลายไฟล์จะถูกแคชล่วงหน้าโดยโปรแกรมทำงานของบริการ ณ เวลาที่ติดตั้ง
โปรแกรมทำงานของบริการจะแคชทรัพยากร Dependency ของ Shell ของแอปพลิเคชันล่วงหน้าเมื่อติดตั้ง คำขอการแคชล่วงหน้าคือ 2 แถวสุดท้าย และไอคอนรูปเฟืองถัดจากคำขอระบุว่าโปรแกรมทำงานของบริการจัดการคำขอ

การแคช HTML, CSS และ JavaScript ของ Application Shell ล่วงหน้านั้นทำได้ในเกือบทุกเวิร์กโฟลว์ รวมถึงโปรเจ็กต์ที่ใช้ Bundler ขณะที่ศึกษาเอกสารประกอบ คุณจะได้เรียนรู้วิธีใช้ Workbox โดยตรงเพื่อตั้งค่า Toolchain เพื่อสร้าง Service Worker ที่เหมาะกับโปรเจ็กต์ของคุณที่สุด ไม่ว่าจะเป็น SPA หรือไม่ก็ตาม

บทสรุป

การรวมโมเดล Application Shell กับ Service Worker นั้นเหมาะอย่างยิ่งสำหรับการแคชแบบออฟไลน์ โดยเฉพาะอย่างยิ่งหากคุณรวมฟังก์ชันการสร้างแคชล่วงหน้าเข้ากับระบบที่มุ่งเน้นเครือข่ายเป็นหลัก เปลี่ยนไปใช้กลยุทธ์การแคชสำหรับมาร์กอัปหรือการตอบกลับจาก API ผลลัพธ์ที่ได้คือประสบการณ์การใช้งานที่เสถียรซึ่งจะแสดงผล Application Shell ของคุณในทันทีเมื่อมีการเข้าชมซ้ำ แม้ในสภาวะที่ออฟไลน์