โมดูล ES ใน Service Worker

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

เจฟ พอสนิก
เจฟฟ์ พอสนิก

ที่มา

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

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

Use Case

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

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

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

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

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

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

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

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

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

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