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 cung cấp một số tính năng hỗ trợ mô-đun ES, nhưng không phải trình duyệt nào cũng hỗ trợ mọi nơi mà bạn có thể chạy mã. Cụ thể, tính năng hỗ trợ nhập mô-đun ES bên trong trình chạy dịch vụ của trình duyệt mới bắt đầu được cung cấp rộng rãi hơn.

Bài viết này trình bày chi tiết trạng thái hiện tại của tính năng 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ố điểm cần tránh và các phương pháp hay nhất để phân phối mã trình chạy dịch vụ 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().

Các hạn chế hiện tại

Chỉ nhập tĩnh

Bạn có thể nhập các mô-đun ES theo một trong hai cách: tĩnh bằng cách sử dụng cú pháp import ... from '...' hoặc động bằng cách sử dụ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ể lưu tất cả mã JavaScript cần thiết cho việc triển khai worker dịch vụ vào bộ nhớ đệm một cách ngầm ẩn 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ợ bản đồ nhập

Bản đồ nhập cho phép môi trường thời gian chạy ghi lại chỉ định mô-đun, chẳng hạn như thêm vào đầu URL của CDN ưu tiên mà từ đó có thể tải các mô-đun ES.

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 đã thêm tính năng hỗ trợ trong Bản phát hành Bản dùng thử công nghệ 122 và nhà phát triển có thể 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ẽ hoạt động tốt nếu tất cả trình duyệt đều hỗ trợ các mô-đun ES trong worker dịch vụ, nhưng tại thời điểm viết bài này, điều đó không đúng.

Để 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 mà bạn đang cố gắng nhập đã có sẵn trong các định dạng IIFE hoặc UMD, thì 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_