โมดูล ES ใน Service Worker

ทางเลือกสมัยใหม่สำหรับ ImportScripts()

ที่มา

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

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

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

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

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

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

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

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

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

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

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

แล้วผู้ปฏิบัติงานคนอื่นๆ ล่ะ

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

Chrome และ Edge รองรับโมดูล ES ในผู้ปฏิบัติงานที่แชร์มาตั้งแต่เวอร์ชัน 83 แต่ปัจจุบันยังไม่มีการรองรับเบราว์เซอร์อื่น

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

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

แม้ว่า Chrome และ Edge เวอร์ชัน 89 ขึ้นไปจะรองรับแผนที่การนำเข้า แต่ไม่สามารถใช้กับผู้ปฏิบัติงานบริการได้ในขณะนี้

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

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

Safari เพิ่มการรองรับใน Technology Preview 122 Release และนักพัฒนาซอฟต์แวร์น่าจะได้เห็นฟังก์ชันนี้เปิดตัวใน 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 ผ่าน Bundler ที่เข้ากันได้กับโมดูล ES เพื่อสร้างโปรแกรมทำงานของบริการที่มีโค้ดโมดูลทั้งหมดในบรรทัดและจะทำงานในเบราว์เซอร์รุ่นเก่าได้ หรือถ้าโมดูลที่คุณพยายามนำเข้ามีการรวมกลุ่มไว้ในรูปแบบ IIFE หรือ UMD อยู่แล้ว คุณสามารถนำเข้าโดยใช้ importScripts()

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

_รูปภาพโดย Vlado Paunovic ใน Unsplash_