UNPKG

@qwik.dev/core

Version:

An open source framework for building instant loading web apps at any scale, without the extra effort.

319 lines (318 loc) 9.88 kB
import { inlinedQrl, _captures, implicit$FirstArg } from "@qwik.dev/core"; import workerUrl from "./worker.js?worker&url"; import { _serialize } from "@qwik.dev/core/internal"; import nodeWorkerAssetUrl from "./worker.node.js?worker&url"; const browserGlobals$1 = globalThis; const sanitizeWorkerArgs = (args) => { const SubmitEventConstructor = browserGlobals$1.SubmitEvent; const HTMLFormElementConstructor = browserGlobals$1.HTMLFormElement; const EventConstructor = browserGlobals$1.Event; const NodeConstructor = browserGlobals$1.Node; const sanitizedArgs = new Array(args.length); for (let i = 0; i < args.length; i++) { const arg = args[i]; if (SubmitEventConstructor && HTMLFormElementConstructor && arg instanceof SubmitEventConstructor && arg.target instanceof HTMLFormElementConstructor) { sanitizedArgs[i] = new FormData(arg.target); } else if (EventConstructor && arg instanceof EventConstructor) { sanitizedArgs[i] = null; } else if (NodeConstructor && arg instanceof NodeConstructor) { sanitizedArgs[i] = null; } else { sanitizedArgs[i] = arg; } } return sanitizedArgs; }; const qwikWorkers = /* @__PURE__ */ new Map(); const pendingWorkers = /* @__PURE__ */ new Map(); let nextWorkerRequestId = 0; const getWorkerRequestId = () => ++nextWorkerRequestId; const getWorkerHash = (qrl) => qrl.getHash(); const getWorkerName = (qrl) => `worker$(${qrl.getSymbol()})`; const getOrCreateWorker = (qrl, createWorker) => { const workerHash = getWorkerHash(qrl); const cachedWorker = qwikWorkers.get(workerHash); if (cachedWorker) { return Promise.resolve(cachedWorker); } const pendingWorker = pendingWorkers.get(workerHash); if (pendingWorker) { return pendingWorker; } const workerPromise = Promise.resolve(createWorker()).then((worker) => { if (worker) { qwikWorkers.set(workerHash, worker); } return worker; }).finally(() => { pendingWorkers.delete(workerHash); }); pendingWorkers.set(workerHash, workerPromise); return workerPromise; }; const isWorkerResponseMessage = (messageData, requestId) => Array.isArray(messageData) && messageData.length === 3 && messageData[0] === requestId; const invokeWorker = async (worker, qrl, args) => { const requestId = getWorkerRequestId(); const data = await _serialize([ qrl, ...args ]); return new Promise((resolve, reject) => { const cleanup = () => { worker.offError(errorHandler); worker.offMessage(messageHandler); }; const errorHandler = (error) => { cleanup(); reject(error); }; const messageHandler = (messageData) => { if (isWorkerResponseMessage(messageData, requestId)) { cleanup(); if (messageData[1]) { resolve(messageData[2]); } else { reject(messageData[2]); } } }; worker.onError(errorHandler); worker.onMessage(messageHandler); worker.postMessage([ requestId, data ]); }); }; const browserGlobals = globalThis; const createBrowserWorkerTransport = (worker) => { const errorListenerMap = /* @__PURE__ */ new Map(); const listenerMap = /* @__PURE__ */ new Map(); return { offError(handler) { const listener = errorListenerMap.get(handler); if (listener) { errorListenerMap.delete(handler); worker.removeEventListener("error", listener); } }, offMessage(handler) { const listener = listenerMap.get(handler); if (listener) { listenerMap.delete(handler); worker.removeEventListener("message", listener); } }, onError(handler) { const listener = (event) => handler(event.error ?? event); errorListenerMap.set(handler, listener); worker.addEventListener("error", listener); }, onMessage(handler) { const listener = (event) => handler(event.data); listenerMap.set(handler, listener); worker.addEventListener("message", listener); }, postMessage(data) { worker.postMessage(data); } }; }; const getBrowserWorker = (qrl) => { const WorkerConstructor = browserGlobals.Worker; if (!WorkerConstructor) { return Promise.resolve(null); } return getOrCreateWorker(qrl, () => createBrowserWorkerTransport(new WorkerConstructor(workerUrl, { name: getWorkerName(qrl), type: "module" }))); }; const tryParseUrl = (value) => { try { return new URL(value); } catch { return null; } }; const getImportMetaDirUrl = (metaUrl) => { const moduleUrl = tryParseUrl(metaUrl); if (!moduleUrl || moduleUrl.protocol !== "file:") { return null; } moduleUrl.pathname = moduleUrl.pathname.slice(0, moduleUrl.pathname.lastIndexOf("/") + 1); return moduleUrl; }; const getPublicBuildPath = (assetUrl) => { const assetsIndex = assetUrl.lastIndexOf("/assets/"); if (assetsIndex === -1) { return null; } return `${assetUrl.slice(0, assetsIndex)}/build/`; }; const getNodeDistUrl$1 = (metaUrl, fsModule) => { if (!fsModule?.existsSync) { return null; } let currentDirUrl = getImportMetaDirUrl(metaUrl); if (!currentDirUrl) { return null; } for (let i = 0; i < 8; i++) { const distUrl = new URL("dist/", currentDirUrl); if (fsModule.existsSync(distUrl)) { return distUrl; } const parentDirUrl = new URL("../", currentDirUrl); if (parentDirUrl.href === currentDirUrl.href) { break; } currentDirUrl = parentDirUrl; } return null; }; const getNodeWorkerUrlFromDist = (assetUrl, distUrl) => { return new URL(`.${assetUrl}`, distUrl); }; const getNodeWorkerQrlBaseUrlFromDist = (assetUrl, distUrl) => { const publicBuildPath = getPublicBuildPath(assetUrl); if (!publicBuildPath) { return null; } return new URL(`.${publicBuildPath}`, distUrl); }; const runtimeGlobals$1 = globalThis; const runtimeImportMeta = import.meta; const nodeWorkerThreadsModuleId = "node:worker_threads"; const nodeFsModuleId = "node:fs"; let resolvedNodeWorkerUrl = void 0; let resolvedNodeDistUrl = void 0; const getNodeWorkerConstructor = () => { const workerThreadsModule = runtimeGlobals$1.process?.getBuiltinModule?.(nodeWorkerThreadsModuleId); return workerThreadsModule?.Worker; }; const getNodeFsModule = () => { return runtimeGlobals$1.process?.getBuiltinModule?.(nodeFsModuleId); }; const getResolvedNodeWorkerModuleUrl = () => { const resolvedUrl = runtimeImportMeta.resolve?.("./worker.node.js"); if (!resolvedUrl) { return null; } const workerUrl2 = tryParseUrl(resolvedUrl); if (!workerUrl2) { return null; } const fsModule = getNodeFsModule(); if (!fsModule?.existsSync?.(workerUrl2)) { return null; } return workerUrl2; }; const getNodeDistUrl = () => { if (resolvedNodeDistUrl !== void 0) { return resolvedNodeDistUrl; } resolvedNodeDistUrl = getNodeDistUrl$1(import.meta.url, getNodeFsModule()); return resolvedNodeDistUrl; }; const getNodeWorkerUrl = () => { if (resolvedNodeWorkerUrl != void 0) { return resolvedNodeWorkerUrl; } const resolvedModuleUrl = getResolvedNodeWorkerModuleUrl(); if (resolvedModuleUrl) { resolvedNodeWorkerUrl = resolvedModuleUrl; return resolvedNodeWorkerUrl; } if (nodeWorkerAssetUrl.startsWith("/")) { const distUrl = getNodeDistUrl(); if (distUrl) { resolvedNodeWorkerUrl = getNodeWorkerUrlFromDist(nodeWorkerAssetUrl, distUrl); return resolvedNodeWorkerUrl; } } resolvedNodeWorkerUrl = new URL(nodeWorkerAssetUrl, import.meta.url); return resolvedNodeWorkerUrl; }; const getNodeWorkerQrlBaseUrl = () => { const resolvedModuleUrl = getResolvedNodeWorkerModuleUrl(); if (resolvedModuleUrl) { return new URL("../build/", resolvedModuleUrl); } if (nodeWorkerAssetUrl.startsWith("/")) { const distUrl = getNodeDistUrl(); const qrlBaseUrl = distUrl && getNodeWorkerQrlBaseUrlFromDist(nodeWorkerAssetUrl, distUrl); if (qrlBaseUrl) { return qrlBaseUrl; } } return new URL("../build/", getNodeWorkerUrl()); }; const createNodeWorkerTransport = (worker) => { return { offError(handler) { worker.off("error", handler); }, offMessage(handler) { worker.off("message", handler); }, onError(handler) { worker.on("error", handler); }, onMessage(handler) { worker.on("message", handler); }, postMessage(data) { worker.postMessage(data); } }; }; const getNodeWorker = (qrl) => { return getOrCreateWorker(qrl, () => { const WorkerConstructor = getNodeWorkerConstructor(); if (!WorkerConstructor) { return null; } const worker = new WorkerConstructor(getNodeWorkerUrl(), { name: getWorkerName(qrl), workerData: { qrlBaseUrl: getNodeWorkerQrlBaseUrl().href } }); worker.unref(); return createNodeWorkerTransport(worker); }); }; const runtimeGlobals = globalThis; const isBrowserRuntime = () => !!runtimeGlobals.document; const isBunRuntime = () => !!runtimeGlobals.process?.versions?.bun; const isDenoRuntime = () => !!runtimeGlobals.Deno?.version?.deno; const isNodeRuntime = () => !!runtimeGlobals.process?.versions?.node && !isBunRuntime() && !isDenoRuntime(); const getWorkerTransport = async (qrl) => { if (isNodeRuntime()) { return getNodeWorker(qrl); } if (isBrowserRuntime()) { return getBrowserWorker(qrl); } return null; }; const workerQrl = (qrl) => { return /* @__PURE__ */ inlinedQrl(async (...args) => { const qrl2 = _captures[0]; const filtered = sanitizeWorkerArgs(args); const worker = await getWorkerTransport(qrl2); if (!worker) { return qrl2(...filtered); } return invokeWorker(worker, qrl2, filtered); }, "workerQrl_lGZKoP3eM7I", [ qrl ]); }; const worker$ = implicit$FirstArg(workerQrl); export { worker$, workerQrl };