โมดูล ES ใน Service Worker

ทางเลือกที่ทันสมัยแทน importScripts()

ฉากหลัง

โมดูล ES เป็นที่ชื่นชอบของนักพัฒนาซอฟต์แวร์มาสักพักแล้ว นอกจากประโยชน์อื่นๆ อีกมากมายแล้ว โมดูลเหล่านี้ยังให้สัญญาเกี่ยวกับรูปแบบโมดูลสากลที่สามารถเผยแพร่โค้ดที่แชร์ได้เพียงครั้งเดียวและเรียกใช้ในเบราว์เซอร์และรันไทม์ทางเลือก เช่น Node.js แม้ว่าเบราว์เซอร์ที่ทันสมัยทั้งหมดจะรองรับโมดูล ES อยู่บ้าง แต่ก็ไม่ได้รองรับทุกที่ที่โค้ดทำงานได้ โดยเฉพาะอย่างยิ่ง การรองรับการนำเข้าโมดูล ES ภายใน Service Worker ของเบราว์เซอร์เพิ่งเริ่มพร้อมใช้งานในวงกว้างมากขึ้น

บทความนี้จะอธิบายรายละเอียดสถานะปัจจุบันของการรองรับโมดูล ES ใน Service Worker ในเบราว์เซอร์ทั่วไป รวมถึงข้อควรระวังที่ควรหลีกเลี่ยง และแนวทางปฏิบัติแนะนำสำหรับการจัดส่งโค้ด Service Worker ที่เข้ากันได้แบบย้อนหลัง

กรณีการใช้งาน

กรณีการใช้งานที่เหมาะสมสำหรับโมดูล ES ภายใน Service Worker คือการโหลดไลบรารีสมัยใหม่หรือโค้ดการกำหนดค่าที่แชร์กับรันไทม์อื่นๆ ที่รองรับโมดูล ES

การพยายามแชร์โค้ดในลักษณะนี้ก่อนที่จะมีโมดูล ES จำเป็นต้องใช้รูปแบบโมดูล "สากล" ที่เก่ากว่า เช่น UMD ซึ่งมีต้นแบบที่ไม่จำเป็น และการเขียนโค้ดที่ทำการเปลี่ยนแปลงตัวแปรที่แสดงต่อสาธารณะ

สคริปต์ที่นำเข้าผ่านโมดูล ES สามารถทริกเกอร์ขั้นตอนอัปเดต Service Worker ได้หากเนื้อหามีการเปลี่ยนแปลง ซึ่งตรงกับลักษณะการทำงานของ importScripts()

ข้อจำกัดในปัจจุบัน

การนำเข้าแบบคงที่เท่านั้น

โมดูล ES สามารถนำเข้าได้ 2 วิธี ได้แก่ แบบคงที่ โดยใช้ไวยากรณ์ import ... from '...' หรือ แบบไดนามิก โดยใช้เมธอด import() ภายใน Service Worker ขณะนี้รองรับเฉพาะไวยากรณ์แบบคงที่เท่านั้น

ข้อจำกัดนี้คล้ายกับข้อจำกัดที่คล้ายกันในการใช้งาน importScripts() การเรียกใช้ importScripts() แบบไดนามิกจะไม่ทำงานภายใน Service Worker และการเรียกใช้ importScripts() ทั้งหมดซึ่งเป็นแบบซิงโครนัสโดยเนื้อแท้จะต้องเสร็จสมบูรณ์ก่อนที่ Service Worker จะเสร็จสิ้นระยะ install ข้อจำกัดนี้ช่วยให้มั่นใจว่าเบราว์เซอร์รู้จักและสามารถแคชโค้ด JavaScript ทั้งหมดที่จำเป็นสำหรับการติดตั้งใช้งาน Service Worker ในระหว่างการติดตั้งได้โดยนัย

ในที่สุด ข้อจำกัดนี้อาจถูกยกเลิก และอาจอนุญาตให้นำเข้าโมดูล ES แบบไดนามิกได้ ในตอนนี้ โปรดตรวจสอบว่าคุณใช้เฉพาะไวยากรณ์แบบคงที่ภายใน Service Worker เท่านั้น

แล้วพนักงานคนอื่นๆ ล่ะ

การรองรับโมดูล ES ในเวิร์กเกอร์ "เฉพาะ" ซึ่งสร้างขึ้นด้วย new Worker('...', {type: 'module'}) นั้นแพร่หลายมากขึ้น และได้รับการรองรับใน Chrome และ Edge ตั้งแต่เวอร์ชัน 80 รวมถึง Safari เวอร์ชันล่าสุด Dedicated Worker รองรับทั้งการนำเข้าโมดูล ES แบบคงที่และแบบไดนามิก

Chrome และ Edge รองรับโมดูล ES ใน Shared Worker ตั้งแต่เวอร์ชัน 83 แต่ไม่มีเบราว์เซอร์อื่นที่รองรับในขณะนี้

ไม่รองรับแผนที่การนำเข้า

แผนที่การนำเข้าช่วยให้สภาพแวดล้อมรันไทม์เขียนตัวระบุโมดูลใหม่ได้ เช่น เพิ่ม URL ของ CDN ที่ต้องการซึ่งสามารถโหลดโมดูล ES ได้ไว้ข้างหน้า

แม้ว่า Chrome และ Edge เวอร์ชัน 89 ขึ้นไปจะรองรับการจับคู่การนำเข้า แต่ปัจจุบันไม่สามารถใช้กับ Service Worker ได้

การสนับสนุนเบราว์เซอร์

โมดูล ES ใน Service Worker รองรับใน Chrome และ Edge ตั้งแต่เวอร์ชัน 91 เป็นต้นไป

Safari ได้เพิ่มการรองรับในรุ่น Technology Preview 122 และนักพัฒนาแอปควรคาดหวังว่าจะได้เห็นฟังก์ชันนี้เปิดตัวใน Safari เวอร์ชันเสถียรในอนาคต

โค้ดตัวอย่าง

นี่คือตัวอย่างพื้นฐานของการใช้โมดูล ES ที่แชร์ในบริบท window ของเว็บแอป พร้อมทั้งลงทะเบียน Service Worker ที่ใช้โมดูล 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);
    // ...
  })());
});

ความเข้ากันได้แบบย้อนหลัง

ตัวอย่างข้างต้นจะทำงานได้ดีหากเบราว์เซอร์ทั้งหมดรองรับโมดูล ES ใน Service Worker แต่ในขณะที่เขียนบทความนี้ เบราว์เซอร์ยังไม่รองรับ

หากต้องการรองรับเบราว์เซอร์ที่ไม่มีการรองรับในตัว คุณสามารถเรียกใช้สคริปต์ Service Worker ผ่านเครื่องมือรวมที่เข้ากันได้กับโมดูล ES เพื่อสร้าง Service Worker ที่มีโค้ดโมดูลทั้งหมดในบรรทัด และจะทำงานในเบราว์เซอร์รุ่นเก่าได้ หรือหากโมดูลที่คุณพยายามนำเข้ามีอยู่แล้วในรูปแบบ IIFE หรือ UMD คุณสามารถนำเข้าโมดูลดังกล่าวโดยใช้ importScripts()

เมื่อมี Service Worker 2 เวอร์ชันพร้อมใช้งาน (เวอร์ชันหนึ่งใช้โมดูล ES และอีกเวอร์ชันหนึ่งไม่ใช้) คุณจะต้องตรวจหาว่าเบราว์เซอร์ปัจจุบันรองรับอะไร และลงทะเบียนสคริปต์ Service Worker ที่เกี่ยวข้อง แนวทางปฏิบัติแนะนำในการตรวจหาการรองรับยังคงมีการเปลี่ยนแปลงอยู่ แต่คุณสามารถติดตามการพูดคุยในปัญหา GitHub นี้เพื่อดูคำแนะนำได้