React SDK 0.2.1 — แนบ worker ของ MapLibre มาให้ และแผนที่ว่างเปล่าแบบเงียบ ๆ หายไป

worker ของ MapLibre GL JS v6 ถูกแนบมาในแพ็กเกจและลงทะเบียนเองแล้ว onMapLoaded ทำงานเสียที และ TomTom ย้ายมาอยู่บน MapLibre 6 เหมือนตัวอื่น ซึ่งทำให้โหลดได้ภายใต้ตัวแก้ปลายทางแบบ ESM ของ Node ด้วย มี 19 จาก 21 แพ็กเกจที่ขยับ

อัปเดตโมดูลต่าง ๆ ของ MapConductor React SDK แล้ว โดย 19 จาก 21 แพ็กเกจบน npm มีการเปลี่ยนแปลง ส่วนใหญ่เป็นการดูแลรายการพึ่งพา แต่มีการแก้ไขสองจุดรอบ ๆ MapLibre ที่เป็นอาการซึ่งหาสาเหตุได้ยากเมื่อเจอเข้าจริง

เวอร์ชันไม่ได้ถูกจัดให้ตรงกันโดยตั้งใจ react-for-maplibre และ react-for-openlayers อยู่ที่ 0.2.2 ส่วน react-icons และ react-kml คงเดิม ที่เหลืออยู่ที่ 0.2.1 ต่างจาก 0.2.0 ตรงที่เราเลิกให้ทุกแพ็กเกจใช้เลขเดียวกันแล้ว เพราะการขึ้นเวอร์ชันแพ็กเกจที่เนื้อในไม่ได้เปลี่ยน บอกผู้ที่อัปเดตได้เพียงว่า "มีอะไรบางอย่างเปลี่ยนไป" เท่านั้น

แผนที่เหลือแต่สีพื้นหลัง และไม่มีข้อผิดพลาดใด ๆ ถูกโยนออกมา

นี่คือใจความของ react-for-maplibre 0.2.2

MapLibre GL JS v6 แจกจ่าย Web Worker เป็นไฟล์แยก และประกอบ URL ของมันจาก import.meta.url ของตัวเอง เมื่อผ่านบันเดิลเลอร์ ค่านี้จะถูกตรึงตั้งแต่ตอนบิลด์ (เป็นพาธ file:// บน Rspack และเป็นปลายทางของ prebundle บน Vite) ขณะที่ไฟล์จริงของ worker ไม่ได้ถูกสร้างออกมาที่ใดเลย การแก้ปลายทางจึงล้มเหลว

ส่วนที่ยุ่งยากคือ ความล้มเหลวนี้ไม่โยนข้อผิดพลาดใด ๆ จะมีบางอย่างเช่น new Worker("") ถูกสร้างขึ้นเงียบ ๆ และแผนที่หยุดโดยไม่ส่งคำขอไทล์แม้แต่รายการเดียว สิ่งที่เห็นคือแผนที่ที่มีแต่สีพื้นหลัง ถ้าแผงเน็ตเวิร์กแสดงคำขอ .pbf เป็นศูนย์ ก็คืออาการนี้

0.2.2 แนบ worker แบบเบ็ดเสร็จในตัวมากับแพ็กเกจ และลงทะเบียนให้อัตโนมัติเมื่อสร้างแผนที่แรก ไม่ต้องตั้งค่าใด ๆ ทำงานเหมือนกันทั้งบน Vite และ webpack / Rspack ทั้งในโหมด dev และบิลด์สำหรับใช้งานจริง

มีข้อยกเว้นอยู่หนึ่งกรณี คือเมื่อคุณเสิร์ฟ worker จาก URL ของตัวเอง (CDN ที่ใช้ร่วมกัน หรือบิลด์ที่สร้างไฟล์นี้อยู่แล้ว) ให้เรียก setMapLibreWorkerUrl(url) ก่อนสร้างแผนที่แรก แล้ว worker ที่แนบมาจะถูกข้าม และไม่ถูกดาวน์โหลดเลย

ts
import { setMapLibreWorkerUrl } from '@mapconductor/react-for-maplibre';

setMapLibreWorkerUrl('https://cdn.example.com/maplibre-worker.mjs');

สิ่งหนึ่งที่ควรคาดไว้ล่วงหน้า เซิร์ฟเวอร์ dev ของ Vite จะส่ง worker ที่แนบมาผ่านสายงานแปลงไฟล์ ทำให้มีการฉีด import ของ /@vite/client เข้าไปและขนาดไฟล์บวมขึ้น (ราว 478KB → 2.8MB) หน้าตาน่าตกใจแต่ไม่กระทบพฤติกรรมใด ๆ ส่วนบิลด์สำหรับใช้งานจริงจะออกมาเป็นแอสเซตธรรมดา

การส่ง worker ในรูป Blob URL ใช้ไม่ได้บน v6 ตัว worker เริ่มทำงานโดยไม่มีข้อผิดพลาด แต่ก็ยังไม่ส่งคำขอไทล์เลยแม้แต่รายการเดียว จึงต้องเสิร์ฟเป็นไฟล์จริงเท่านั้น

onMapLoaded ไม่เคยทำงานเลย

เป็นของ react-for-maplibre 0.2.2 เช่นกัน

MapLibreProvider.initialize() จะรอ map.once('load') ก่อนจึงสร้างคอนโทรลเลอร์ นั่นแปลว่าเมื่อคอนโทรลเลอร์เกิดขึ้น การโหลดได้จบไปแล้ว ดังนั้น on('load') ที่ setupEventListeners ผูกไว้จึงไม่มีทางทำงานอีก

การตรวจว่า "เริ่มต้นเสร็จแล้วหรือยัง" ในคอนสตรักเตอร์ควรจะรองรับกรณีนี้ แต่กลับไม่ทำงาน เพราะทั้ง loaded() และ isStyleLoaded() คืนค่า false ทันทีหลังโหลด เนื่องจาก isStyleLoaded() ของ MapLibre v6 เรียก Style.loaded() ซึ่งรอจนทุก tileManager ทำงานเสร็จ

แก้แล้วใน 0.2.2 หากคุณใช้ onMapLoaded อยู่ ที่ผ่านมามันไม่เคยถูกเรียกเลย

js-sdk-core 0.2.1 — Service Worker ล้มเมื่อไอคอนมีหลายแบบเกินไป

ไอคอนหมุดถูกส่งไปยัง Service Worker ที่แจกไทล์ในรูปบิตแมป โดยเก็บทีละชิ้นแล้วส่งรวมกันตอนท้าย ดังนั้น เมื่อใช้ไอคอนต่างแบบมากกว่าที่แคชเก็บได้ ชิ้นที่เก็บไว้ก่อนจึงถูกคืนหน่วยความจำไปแล้วตอนที่ส่ง การนำ ImageBitmap ที่ถูกคืนไปแล้วผ่าน structured clone จะโยน DataCloneError และพาการลงทะเบียน Service Worker ล้มไปทั้งหมด

เมื่อไม่มีการลงทะเบียน ไทล์ก็ไม่มาสักแผ่น สิ่งที่เห็นจึงเป็นแผนที่ที่ไม่ขึ้น และอาการจะเกิดก็ต่อเมื่อจำนวนไอคอนต่างแบบเกินขนาดแคช นั่นคือบั๊กชนิดที่ทำงานได้บนเครื่องตัวเอง แต่ไปหยุดตอนใช้งานจริง

การแก้ไม่ใช่การขยายแคช แต่เป็นเรื่องความเป็นเจ้าของ ตอนนี้ข้อมูลที่ส่งจะถือสำเนาของตัวเอง และคืนหน่วยความจำหลังส่งเสร็จ ส่วนที่เป็นของแคชจะไม่ถูกแตะ

TomTom ไม่ได้แบก MapLibre ตัวที่สองอีกต่อไป

ใน 0.2.0 มีเพียง react-for-tomtom ที่ถูกตรึงไว้กับ maplibre-gl 5.x เพราะ @tomtom-org/maps-sdk พึ่งพา maplibre-gl@^5.24.0 การขยับไป 6.x จะทำให้มี MapLibre สองชุดติดตั้งอยู่ และส่งอ็อบเจ็กต์แผนที่ที่ SDK ของ TomTom ไม่ได้คาดไว้

TomTom ย้ายไปใช้ maplibre-gl@^6.4.0 ใน 0.51.5 แล้ว react-for-tomtom 0.2.1 จึงตามไปที่ ^6.6.0 ตอนนี้มันใช้ MapLibre ชุดเดียวกันกับ react-for-maplibre และ react-for-maptiler และหมายเหตุจาก 0.2.0 ก็ไม่จำเป็นอีกต่อไป

ผลพลอยได้คือ react-for-tomtom โหลดได้แล้วภายใต้ตัวแก้ปลายทางแบบ ESM ของ Node ซึ่งใน 0.2.0 ทำไม่ได้ โดยเหตุผลตอนนั้นคือมัน "อ่าน maplibre-gl/package.json ซึ่ง Node จะโหลดให้ก็ต่อเมื่อมี import attribute" วัดผลโดยการ import แพ็กเกจที่เผยแพร่แล้วในโปรเจกต์เปล่า

importrequire()
react-for-tomtom 0.2.0nono
react-for-tomtom 0.2.1yesno

require() ยังคงล้มเหลว เพราะ maplibre-gl v6 เป็น ESM ล้วนและไม่ประกาศทางเข้าแบบ CommonJS ซึ่งเป็นเหตุผลเดียวกับ react-for-maplibre และ react-for-maptiler ทั้งสามตัวนี้ให้ใช้ผ่าน ESM

มีเวอร์ชัน 0.2.1 สี่ตัวที่โค้ดไม่ได้เปลี่ยน

เวอร์ชัน 0.2.1 ของ js-sdk-react, react-geojson, react-heatmap และ react-marker-clustering ส่งมอบ JavaScript ชุดเดียวกับ 0.2.0 สิ่งที่ขยับคือข้อมูลบิลด์ที่แนบอยู่ในแพ็กเกจ ซึ่งการบิลด์ฝั่งเว็บไม่เคยอ่าน จึงไม่ต้องรีบอัปเดต และการอัปเดตก็ไม่มีผลเสีย

SDK แผนที่ที่อัปเดต

ปรับให้เป็นเวอร์ชันใหม่ที่สุดภายในช่วงที่ประกาศไว้ รายการที่ขยับมีดังนี้

รายการพึ่งพา0.2.0ตอนนี้
mapbox-gl^3.15.0^3.29.0
maplibre-gl^6.0.0^6.6.0
cesium^1.131.0^1.144.0
ol^10.2.1^10.10.0
@arcgis/core^5.1.16^5.1.20
@tomtom-org/maps-sdk^0.51.0^0.51.5
azure-maps-control^3.7.0^3.7.4
@turf/turf^7.3.5^7.4.0

สามรายการคงเดิม ได้แก่ leaflet ^1.9.4, @googlemaps/js-api-loader ^2.1.1 และ mappls-web-maps ^3.8.1 เพราะต้นทางยังไม่ขยับ ส่วน peerDependencies ของ React ยังคงเป็น ^18.0.0 || ^19.0.0 ที่เปลี่ยนคือเวอร์ชันที่ใช้ตอนพัฒนาเท่านั้น (19.2.7 → 19.2.8)

แพ็กเกจและ SDK แผนที่ที่แต่ละตัวใช้

แพ็กเกจเวอร์ชันSDK แผนที่รีโพซิทอรี
@mapconductor/js-sdk-core0.2.1js-sdk-core
@mapconductor/js-sdk-react0.2.1js-sdk-react
@mapconductor/react-for-arcgis0.2.1@arcgis/core ^5.1.20react-for-arcgis
@mapconductor/react-for-azuremaps0.2.1azure-maps-control ^3.7.4react-for-azuremaps
@mapconductor/react-for-cesium0.2.1cesium ^1.144.0react-for-cesium
@mapconductor/react-for-googlemaps0.2.1@googlemaps/js-api-loader ^2.1.1react-for-googlemaps
@mapconductor/react-for-here0.2.1CDN (global H)react-for-here
@mapconductor/react-for-leaflet0.2.1leaflet ^1.9.4react-for-leaflet
@mapconductor/react-for-longdo0.2.1CDN (api.longdo.com/map3)react-for-longdo
@mapconductor/react-for-mapbox0.2.1mapbox-gl ^3.29.0react-for-mapbox
@mapconductor/react-for-mapkit0.2.1CDN (cdn.apple-mapkit.com)react-for-mapkit
@mapconductor/react-for-maplibre0.2.2maplibre-gl ^6.6.0react-for-maplibre
@mapconductor/react-for-mappls0.2.1mappls-web-maps ^3.8.1react-for-mappls
@mapconductor/react-for-maptiler0.2.1maplibre-gl ^6.6.0react-for-maptiler
@mapconductor/react-for-openlayers0.2.2ol ^10.10.0react-for-openlayers
@mapconductor/react-for-tomtom0.2.1@tomtom-org/maps-sdk ^0.51.5, maplibre-gl ^6.6.0react-for-tomtom
@mapconductor/react-geojson0.2.1react-geojson
@mapconductor/react-heatmap0.2.1react-heatmap
@mapconductor/react-icons0.2.0react-icons
@mapconductor/react-kml0.2.0react-kml
@mapconductor/react-marker-clustering0.2.1react-marker-clustering

HERE, Apple MapKit JS และ Longdo ไม่มี SDK แผนที่เป็นรายการพึ่งพา เพราะ SDK เหล่านั้นไม่ได้แจกจ่ายผ่าน npm แต่โหลดจาก CDN ของผู้ให้บริการตอนรันไทม์ เวอร์ชันที่ทำงานจริงจึงเป็นเวอร์ชันที่ผู้ให้บริการเสิร์ฟอยู่

วิธีอัปเดต

bash
npm install @mapconductor/js-sdk-core@latest @mapconductor/js-sdk-react@latest \
  @mapconductor/react-for-maplibre@latest

js-sdk-core ก็ขึ้นเป็น 0.2.1 แล้ว โดยมีการแก้ Service Worker ข้างต้นอยู่ในนั้น ถ้าคุณใช้ไอคอนหมุดหลายแบบ ควรอัปเดตตัวนี้ด้วย

พฤติกรรมด้าน ESM, CommonJS และ SSR ยังเหมือนกับ 0.2.0 ยกเว้น react-for-tomtom ที่กล่าวไว้ข้างต้น ตารางฉบับเต็มว่าแพ็กเกจใดโหลดได้และโหลดไม่ได้นอกบันเดิลเลอร์ อยู่ใน บทความ React SDK 0.2.0 แต่ละแพ็กเกจอยู่ในรีโพซิทอรีของตัวเอง ดูได้ที่ github.com/MapConductor