import {type AddProtocolAction, config} from './config.ts'; import type {default as MaplibreWorker} from '../source/worker.ts'; import type {WorkerSourceConstructor} from '../source/worker_source.ts'; import type {GetResourceResponse, RequestParameters} from './ajax.ts'; export interface WorkerGlobalScopeInterface { registerWorkerSource: (sourceName: string, sourceConstructor: WorkerSourceConstructor) => void; registerRTLTextPlugin: (_: any) => void; addProtocol: (customProtocol: string, loadFn: AddProtocolAction) => void; removeProtocol: (customProtocol: string) => void; makeRequest: (request: RequestParameters, abortController: AbortController) => Promise>; worker: MaplibreWorker; } function isCrossOrigin(url: string): boolean { if (!url) return false; const loc = (globalThis as any).location; if (!loc) return false; try { return new URL(url, loc.href).origin !== loc.origin; } catch { return false; } } function defaultWorkerUrl(): string { const moduleUrl = import.meta.url; if (!/^https?:/.test(moduleUrl)) return ''; const workerName = moduleUrl.endsWith('-dev.mjs') ? 'maplibre-gl-worker-dev.mjs' : 'maplibre-gl-worker.mjs'; return new URL(`./${workerName}`, moduleUrl).href; } function createWorker(url: string, asModule: boolean): Worker { if (asModule) { try { return new Worker(url, {type: 'module'}); } catch (e) { console.warn('Module worker not supported, falling back to classic worker', e); } } return new Worker(url); } async function fetchAsBlobUrl(url: string): Promise { const response = await fetch(url); if (!response.ok) { throw new Error(`Failed to fetch worker script (${response.status}): ${url}`); } const code = await response.text(); const blob = new Blob([code], {type: 'text/javascript'}); return URL.createObjectURL(blob); } function importAsBlobUrl(url: string): string { const blob = new Blob([`import ${JSON.stringify(new URL(url, import.meta.url).href)}`], {type: 'text/javascript'}); return URL.createObjectURL(blob); } export async function workerFactory(): Promise { const url = config.WORKER_URL || defaultWorkerUrl(); const asModule = url?.endsWith('.cjs') ? false : true; if (!isCrossOrigin(url)) { return createWorker(url, asModule); } if (asModule) { const blobUrl = importAsBlobUrl(url); try { return createWorker(blobUrl, asModule); } finally { URL.revokeObjectURL(blobUrl); } } const blobUrl = await fetchAsBlobUrl(url); try { return createWorker(blobUrl, asModule); } finally { URL.revokeObjectURL(blobUrl); } }