Trình chạy dịch vụ và mô hình shell ứng dụng

Đặc điểm cấu trúc phổ biến của ứng dụng web trang đơn (SPA) là tập hợp tối thiểu HTML, CSS và JavaScript cần thiết để hỗ trợ chức năng chung của ứng dụng. Trong thực tế, các thành phần này thường là tiêu đề, thành phần điều hướng và các thành phần giao diện người dùng phổ biến khác trên tất cả các trang. Khi một trình chạy dịch vụ lưu trước vào bộ nhớ đệm HTML tối thiểu của giao diện người dùng và các phần tử phụ thuộc, chúng tôi gọi đây là giao diện ứng dụng.

Sơ đồ về một shell ứng dụng. Đây là ảnh chụp màn hình của một trang web có tiêu đề ở trên cùng và vùng nội dung ở dưới cùng. Tiêu đề được gắn nhãn 'Application Shell', trong khi tiêu đề dưới cùng có nhãn 'Content'.

Giao diện ứng dụng đóng vai trò quan trọng trong hiệu suất cảm nhận của một ứng dụng web. Đây là thành phần tải đầu tiên, nên cũng là thành phần đầu tiên mà người dùng nhìn thấy trong khi chờ nội dung hiển thị trên giao diện người dùng.

Mặc dù shell ứng dụng tải nhanh — miễn là đã có mạng và ít nhất là khá nhanh — một trình chạy dịch vụ lưu trước vào bộ nhớ đệm của giao diện ứng dụng và các tài sản liên quan mang lại cho mô hình shell ứng dụng những lợi ích bổ sung sau:

  • Hiệu suất đáng tin cậy, nhất quán cho các lượt truy cập lặp lại. Trong lần truy cập đầu tiên vào một ứng dụng chưa cài đặt trình chạy dịch vụ, mã đánh dấu của ứng dụng đó và các phần tử liên quan của ứng dụng đó phải được tải từ mạng trước khi trình chạy dịch vụ đó có thể lưu chúng vào bộ nhớ đệm. Tuy nhiên, các lượt truy cập lặp lại sẽ lấy giao diện ứng dụng từ bộ nhớ đệm, nghĩa là quá trình tải và kết xuất sẽ diễn ra ngay lập tức.
  • Khả năng truy cập đáng tin cậy vào chức năng trong tình huống không có mạng. Đôi khi, kết nối Internet chập chờn hoặc hoàn toàn không có kết nối Internet khiến màn hình hiển thị đáng sợ "chúng tôi không thể tìm thấy trang web đó" vẫn ngả người. Mô hình shell ứng dụng giải quyết vấn đề này bằng cách phản hồi mọi yêu cầu điều hướng bằng mã đánh dấu shell ứng dụng từ bộ nhớ đệm. Ngay cả khi ai đó truy cập vào một URL trong ứng dụng web của bạn mà họ chưa bao giờ đến trước đây, shell ứng dụng sẽ được phân phát từ bộ nhớ đệm và có thể được chứa nội dung hữu ích.

Trường hợp nên sử dụng mô hình shell ứng dụng

Giao diện ứng dụng hợp lý nhất khi bạn có các phần tử giao diện người dùng phổ biến không thay đổi giữa các tuyến, nhưng nội dung thì có. Hầu hết các SPA đều có thể sử dụng hiệu quả mô hình shell ứng dụng đã có.

Nếu điều này mô tả dự án của bạn và bạn muốn thêm một trình chạy dịch vụ để nâng cao độ tin cậy và hiệu suất của dự án, shell ứng dụng phải:

  • Tải nhanh.
  • Sử dụng các thành phần tĩnh từ một thực thể Cache.
  • Bao gồm các thành phần giao diện phổ biến như tiêu đề và thanh bên, tách biệt với nội dung của trang.
  • Truy xuất và hiển thị nội dung theo trang cụ thể.
  • Nếu thích hợp, bạn có thể lưu nội dung động vào bộ nhớ đệm để xem ngoại tuyến.

Giao diện ứng dụng tải động nội dung trang cụ thể thông qua API hoặc nội dung được đóng gói trong JavaScript. Cũng nên tự cập nhật theo nghĩa là nếu mã đánh dấu của shell ứng dụng thay đổi, bản cập nhật của trình chạy dịch vụ sẽ chọn shell ứng dụng mới và tự động lưu vào bộ nhớ đệm.

Tạo giao diện ứng dụng

Giao diện ứng dụng phải tồn tại độc lập với nội dung, nhưng cung cấp cơ sở cho nội dung để được điền trong đó. Tốt nhất là màn hình nhỏ nhất có thể nhưng vẫn cung cấp đủ nội dung có ý nghĩa trong lần tải xuống ban đầu để người dùng hiểu rằng trải nghiệm đang tải nhanh.

Mức cân bằng phù hợp phụ thuộc vào ứng dụng của bạn. Giao diện ứng dụng cho ứng dụng Trained To Thrill của Jake Archibald bao gồm tiêu đề với nút làm mới để lấy nội dung mới từ Flickr.

Ảnh chụp màn hình của ứng dụng web Trained to Thrill ở hai trạng thái khác nhau. Ở bên trái, chỉ hiển thị shell ứng dụng đã lưu vào bộ nhớ đệm mà không có nội dung nào được điền. Ở bên phải, nội dung (một vài hình ảnh về một số chuyến tàu) được tải động vào vùng nội dung của giao diện ứng dụng.

Mã đánh dấu shell ứng dụng sẽ thay đổi tuỳ theo dự án, nhưng sau đây là một ví dụ về tệp index.html cung cấp mã nguyên mẫu của ứng dụng:

​​<!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>

Tuy nhiên, khi bạn tạo một shell ứng dụng cho dự án, lớp đó phải có các đặc điểm sau:

  • HTML nên có các khu vực tách biệt rõ ràng cho các phần tử giao diện người dùng riêng lẻ. Trong ví dụ trên, các thành phần này bao gồm tiêu đề, thành phần điều hướng, vùng nội dung chính và không gian của "vòng quay" đang tải, chỉ xuất hiện khi nội dung đang tải.
  • JavaScript và CSS ban đầu được tải cho giao diện ứng dụng phải là tối thiểu và chỉ liên quan đến chức năng của chính giao diện ứng dụng đó chứ không phải nội dung. Điều này đảm bảo ứng dụng kết xuất shell nhanh nhất có thể và giảm thiểu công việc của luồng chính cho đến khi nội dung xuất hiện.
  • Tập lệnh cùng dòng đăng ký một trình chạy dịch vụ.

Sau khi shell ứng dụng được tạo, bạn có thể tạo một trình chạy dịch vụ để lưu cả trình chạy và nội dung của trình chạy vào bộ nhớ đệm.

Lưu shell ứng dụng vào bộ nhớ đệm

Giao diện ứng dụng và các nội dung bắt buộc của nó là những gì mà worker cần lưu vào bộ nhớ đệm ngay lập tức tại thời điểm cài đặt. Giả sử một shell ứng dụng như ví dụ trên, hãy xem cách thực hiện việc này trong ví dụ cơ bản về Workbox bằng 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.`);
});

Cấu hình được lưu trữ trong build-sw.js sẽ nhập CSS và JavaScript của ứng dụng, bao gồm cả tệp đánh dấu shell ứng dụng có trong shell.html. Tập lệnh được thực thi bằng Nút như sau:

node build-sw.js

Trình chạy dịch vụ đã tạo được ghi vào ./dist/sw.js và sẽ ghi lại thông báo sau khi hoàn tất:

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

Khi trang tải, trình chạy dịch vụ sẽ lưu trước mã đánh dấu shell ứng dụng và các phần phụ thuộc của mã đó vào bộ nhớ đệm:

Ảnh chụp màn hình bảng điều khiển mạng trong Công cụ cho nhà phát triển của Chrome cho thấy danh sách các thành phần được tải xuống từ mạng. Các thành phần do worker dịch vụ lưu trước vào bộ nhớ đệm được phân biệt với các thành phần khác có biểu tượng bánh răng ở bên trái trong hàng. Một số tệp JavaScript và CSS được trình chạy dịch vụ lưu trước vào bộ nhớ đệm tại thời điểm cài đặt.
Trình chạy dịch vụ sẽ lưu trước các phần phụ thuộc của shell ứng dụng vào bộ nhớ đệm tại thời điểm cài đặt. Yêu cầu lưu trước vào bộ nhớ đệm là 2 hàng cuối cùng và biểu tượng bánh răng bên cạnh yêu cầu cho biết trình chạy dịch vụ đã xử lý yêu cầu.

Việc lưu trước HTML, CSS và JavaScript của ứng dụng là có thể thực hiện trong hầu hết mọi quy trình công việc, bao gồm cả các dự án sử dụng trình đóng gói. Khi xem tài liệu này, bạn sẽ tìm hiểu cách trực tiếp sử dụng Workbox để thiết lập chuỗi công cụ nhằm tạo một trình chạy dịch vụ phù hợp nhất cho dự án của bạn, bất kể đó có phải là SPA hay không.

Kết luận

Việc kết hợp mô hình shell ứng dụng với một trình chạy dịch vụ là một cách hiệu quả để lưu vào bộ nhớ đệm khi không có kết nối mạng, đặc biệt là nếu bạn kết hợp chức năng lưu trước vào bộ nhớ đệm với chiến lược ưu tiên mạng, quay lại chiến lược bộ nhớ đệm cho các phản hồi đánh dấu hoặc API. Kết quả là một trải nghiệm nhanh đáng tin cậy sẽ ngay lập tức hiển thị giao diện ứng dụng của bạn trong các lần truy cập lặp lại, ngay cả trong điều kiện ngoại tuyến.