Mô-đun ES trong trình chạy dịch vụ

Một giải pháp thay thế hiện đại cho importScripts().

Thông tin khái quát

Mô-đun ES đã được các nhà phát triển yêu thích trong một thời gian. Ngoài một số lợi ích khác, các mô-đun này hứa hẹn mang đến một định dạng mô-đun phổ quát, trong đó mã dùng chung có thể được phát hành một lần và chạy trong trình duyệt cũng như trong các môi trường thời gian chạy thay thế như Node.js. Mặc dù tất cả trình duyệt hiện đại đều hỗ trợ một số mô-đun ES, nhưng không phải tất cả trình duyệt đều hỗ trợ mọi nơi có thể chạy mã. Cụ thể, chúng tôi mới chỉ bắt đầu cung cấp rộng rãi tính năng hỗ trợ nhập các mô-đun ES bên trong trình chạy dịch vụ của trình duyệt.

Bài viết này trình bày chi tiết về trạng thái hiện tại của việc hỗ trợ mô-đun ES trong trình chạy dịch vụ trên các trình duyệt phổ biến, cùng với một số lỗi cần tránh, cũng như các phương pháp hay nhất để vận chuyển mã của trình chạy dịch vụ có khả năng tương thích ngược.

Trường hợp sử dụng

Trường hợp sử dụng lý tưởng cho các mô-đun ES bên trong trình chạy dịch vụ là để tải một thư viện hiện đại hoặc mã cấu hình được chia sẻ với các môi trường thời gian chạy khác hỗ trợ các mô-đun ES.

Việc cố gắng chia sẻ mã theo cách này trước các mô-đun ES đòi hỏi phải sử dụng các định dạng mô-đun "phổ quát" cũ hơn như UMD bao gồm mã nguyên mẫu không cần thiết và viết mã đã thực hiện các thay đổi đối với các biến được hiển thị trên toàn cầu.

Các tập lệnh được nhập qua mô-đun ES có thể kích hoạt luồng cập nhật của worker dịch vụ nếu nội dung của các tập lệnh đó thay đổi, khớp với hành vi của importScripts().

Hạn chế hiện tại

Chỉ nhập dữ liệu tĩnh

Bạn có thể nhập mô-đun ES theo một trong hai cách: tĩnh bằng cú pháp import ... from '...' hoặc động bằng phương thức import(). Bên trong trình chạy dịch vụ, hiện chỉ hỗ trợ cú pháp tĩnh.

Giới hạn này tương tự như một hạn chế tương tự đối với việc sử dụng importScripts(). Các lệnh gọi động đến importScripts() không hoạt động bên trong worker dịch vụ và tất cả lệnh gọi importScripts() vốn có tính đồng bộ phải hoàn tất trước khi worker dịch vụ hoàn tất giai đoạn install. Quy định hạn chế này đảm bảo rằng trình duyệt biết và có thể ngầm lưu vào bộ nhớ đệm tất cả mã JavaScript cần thiết để triển khai trình chạy dịch vụ trong quá trình cài đặt.

Cuối cùng, quy định hạn chế này có thể được gỡ bỏ và việc nhập mô-đun ES động có thể được cho phép. Hiện tại, hãy đảm bảo rằng bạn chỉ sử dụng cú pháp tĩnh bên trong worker dịch vụ.

Còn các worker khác thì sao?

Hỗ trợ cho các mô-đun ES trong worker "dành riêng" (những mô-đun được tạo bằng new Worker('...', {type: 'module'})) phổ biến hơn và đã được hỗ trợ trong Chrome và Edge kể từ phiên bản 80, cũng như các phiên bản gần đây của Safari. Cả tính năng nhập mô-đun ES tĩnh và động đều được hỗ trợ trong worker chuyên dụng.

Chrome và Edge đã hỗ trợ các mô-đun ES trong worker dùng chung kể từ phiên bản 83, nhưng không có trình duyệt nào khác hỗ trợ tại thời điểm này.

Không hỗ trợ nhập bản đồ

Nhập bản đồ cho phép các môi trường thời gian chạy viết lại thông số mô-đun, chẳng hạn như thêm vào trước URL của CDN ưa thích mà từ đó các mô-đun ES có thể được tải.

Mặc dù Chrome và Edge phiên bản 89 trở lên hỗ trợ bản đồ nhập, nhưng hiện tại bạn không thể sử dụng các bản đồ này với worker dịch vụ.

Hỗ trợ trình duyệt

Các mô-đun ES trong trình chạy dịch vụ được hỗ trợ trong Chrome và Edge kể từ phiên bản 91.

Safari đã hỗ trợ thêm trong Bản phát hành dùng thử công nghệ 122 và nhà phát triển dự kiến sẽ thấy chức năng này được phát hành trong phiên bản Safari ổn định trong tương lai.

Mã mẫu

Đây là ví dụ cơ bản về cách sử dụng mô-đun ES dùng chung trong ngữ cảnh window của ứng dụng web, đồng thời đăng ký một worker dịch vụ sử dụng cùng một mô-đun ES:

// Inside config.js:
export const cacheName = 'my-cache';
// Inside your web app:
<script type="module">
  import {cacheName} from './config.js';
  // Do something with cacheName.

  await navigator.serviceWorker.register('es-module-sw.js', {
    type: 'module',
  });
</script>
// Inside es-module-sw.js:
import {cacheName} from './config.js';

self.addEventListener('install', (event) => {
  event.waitUntil((async () => {
    const cache = await caches.open(cacheName);
    // ...
  })());
});

Khả năng tương thích ngược

Ví dụ trên sẽ phù hợp nếu tất cả các trình duyệt đều hỗ trợ mô-đun ES trong service worker, nhưng tại thời điểm viết bài này, thì không đúng như vậy.

Để hỗ trợ các trình duyệt không có tính năng hỗ trợ tích hợp, bạn có thể chạy tập lệnh trình chạy dịch vụ thông qua một trình đóng gói tương thích với mô-đun ES để tạo một trình chạy dịch vụ bao gồm tất cả mã mô-đun cùng dòng và sẽ hoạt động trong các trình duyệt cũ. Ngoài ra, nếu các mô-đun bạn đang cố gắng nhập đã có sẵn trong các định dạng IIFE hoặc UMD, bạn có thể nhập các mô-đun đó bằng importScripts().

Sau khi có hai phiên bản của trình chạy dịch vụ (một phiên bản sử dụng mô-đun ES và phiên bản còn lại không sử dụng), bạn cần phát hiện những tính năng mà trình duyệt hiện tại hỗ trợ và đăng ký tập lệnh trình chạy dịch vụ tương ứng. Các phương pháp hay nhất để phát hiện tính năng hỗ trợ hiện đang thay đổi, nhưng bạn có thể theo dõi nội dung thảo luận trong vấn đề trên GitHub này để biết các đề xuất.

_Ảnh chụp của Vlado Paunovic trên Unsplash_