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

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

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

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

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

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

กรณีที่ควรใช้ Application Shell Model

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

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

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

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

การสร้าง Application Shell

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

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

ภาพหน้าจอของเว็บแอปที่ผ่านการฝึกให้ตื่นเต้นในสถานะต่างๆ 2 แบบ ทางด้านซ้าย คุณจะเห็นเฉพาะ Application 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 และเนื้อหาที่จำเป็นคือสิ่งที่โปรแกรมทำงานของบริการควรแคชล่วงหน้าทันทีเมื่อติดตั้ง สมมติว่า Application 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.

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

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

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

บทสรุป

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