site-panzai/node_modules/unhead/dist/shared/unhead.B0o2oYhg.mjs

318 lines
9.9 KiB
JavaScript
Raw Permalink Normal View History

2026-11-13 13:57:04 +01:00
import { S as ScriptNetworkEvents } from './unhead.AvDFlk_u.mjs';
function NOOP() {
}
function replayRecordings(target, stack) {
stack.forEach((recordings) => {
let context = target;
let prevContext = target;
recordings.forEach(({ type, key, args }) => {
if (type === "get") {
prevContext = context;
context = context[key];
} else if (type === "apply") {
context = Reflect.apply(context, prevContext, args);
}
});
});
}
function walk(root, path) {
let owner;
let value = root;
for (const key of path) {
if (value == null)
return { owner: void 0, value: void 0 };
owner = value;
value = value[key];
}
return { owner, value };
}
function createScriptProxy(initial = {}) {
const stack = [];
let instance;
let stackIdx = -1;
function node(path) {
const children = /* @__PURE__ */ new Map();
return new Proxy(NOOP, {
get(_, prop) {
if (instance) {
const { value } = walk(instance, path);
const result = value == null ? void 0 : Reflect.get(value, prop, value);
if (typeof result !== "function")
return result;
} else if (!path.length) {
const result = Reflect.get(initial, prop);
if (typeof result !== "undefined")
return result;
stackIdx++;
stack[stackIdx] = [{ type: "get", key: prop }];
} else {
stack[stackIdx].push({ type: "get", key: prop });
}
let child = children.get(prop);
if (!child) {
child = node([...path, prop]);
children.set(prop, child);
}
return child;
},
apply(_, __, args) {
if (instance) {
const { owner, value } = walk(instance, path);
if (typeof value === "function")
Reflect.apply(value, owner, args);
} else {
stack[stackIdx].push({ type: "apply", key: "", args });
}
return void 0;
}
});
}
return {
proxy: node([]),
stack,
resolve(api) {
instance = api;
replayRecordings(api, stack);
stack.length = 0;
}
};
}
function resolveScriptKey(input) {
return input.key || input.src || (typeof input.innerHTML === "string" ? input.innerHTML : "");
}
const PreconnectServerModes = ["preconnect", "dns-prefetch"];
function useScript(head, _input, _options) {
const input = typeof _input === "string" ? { src: _input } : _input;
const options = _options || {};
const id = resolveScriptKey(input);
const scripts = head._scripts || (head._scripts = /* @__PURE__ */ Object.create(null));
const prevScript = Object.prototype.hasOwnProperty.call(scripts, id) ? scripts[id] : void 0;
if (prevScript) {
prevScript.setupTriggerHandler(options.trigger);
return prevScript;
}
options.beforeInit?.();
const syncStatus = (s) => {
script.status = s;
head.hooks.callHook(`script:updated`, hookCtx);
};
ScriptNetworkEvents.forEach((fn) => {
const k = fn;
const _fn = typeof input[k] === "function" ? input[k].bind(options.eventContext) : null;
input[k] = (e) => {
if (script.status === "removed")
return;
syncStatus(fn === "onload" ? "loaded" : fn === "onerror" ? "error" : "loading");
_fn?.(e);
};
});
const _cbs = { loaded: [], error: [] };
const _uniqueCbs = /* @__PURE__ */ new Set();
const _registerCb = (key, cb, options2) => {
if (head.ssr) {
return;
}
let uniqueKey;
if (options2?.key) {
uniqueKey = `${key}:${options2.key}`;
if (_uniqueCbs.has(uniqueKey)) {
return;
}
_uniqueCbs.add(uniqueKey);
}
if (_cbs[key]) {
_cbs[key].push(cb);
return () => {
const idx = _cbs[key]?.indexOf(cb) ?? -1;
if (idx !== -1)
_cbs[key]?.splice(idx, 1);
if (uniqueKey)
_uniqueCbs.delete(uniqueKey);
};
}
if (key === "loaded" && script.status === "loaded")
cb(script.instance);
else if (key === "error" && script.status === "error")
cb();
return () => {
if (uniqueKey)
_uniqueCbs.delete(uniqueKey);
};
};
const loadPromise = new Promise((resolve) => {
if (head.ssr)
return;
const emit = (api) => queueMicrotask(() => resolve(api));
const _ = head.hooks.hook("script:updated", ({ script: updatedScript }) => {
if (updatedScript !== script)
return;
const status = updatedScript.status;
if (status === "loaded" || status === "error" || status === "removed") {
if (status === "loaded") {
if (typeof options.use === "function") {
const api = options.use();
if (api) {
emit(api);
}
} else {
emit({});
}
} else if (status === "error") {
resolve(false);
} else if (status === "removed") {
resolve(false);
}
_();
}
});
});
const script = {
_loadPromise: loadPromise,
instance: !head.ssr && options?.use?.() || null,
proxy: null,
id,
status: "awaitingLoad",
remove() {
const hadEntry = !!script.entry;
script._triggerAbortControllers?.forEach((ac) => ac.abort());
script._triggerAbortControllers?.clear();
script._triggerPromises = [];
script._warmupEl?.dispose();
script._warmupEl = void 0;
if (script.entry) {
script.entry.dispose();
script.entry = void 0;
}
if (scripts[id] === script)
delete scripts[id];
if (script.status !== "removed")
syncStatus("removed");
return hadEntry;
},
warmup(rel) {
const { src } = input;
const isCrossOrigin = !src.startsWith("/") || src.startsWith("//");
const isPreconnect = rel && PreconnectServerModes.includes(rel);
let href = src;
if (!rel || isPreconnect && !isCrossOrigin) {
return;
}
if (isPreconnect) {
const $url = new URL(src);
href = `${$url.protocol}//${$url.host}`;
}
const link = {
href,
rel,
crossorigin: typeof input.crossorigin !== "undefined" ? input.crossorigin : isCrossOrigin ? "anonymous" : void 0,
referrerpolicy: typeof input.referrerpolicy !== "undefined" ? input.referrerpolicy : isCrossOrigin ? "no-referrer" : void 0,
fetchpriority: typeof input.fetchpriority !== "undefined" ? input.fetchpriority : "low",
integrity: input.integrity,
as: rel === "preload" ? "script" : void 0
};
script._warmupEl = head.push({ link: [link] }, { head, tagPriority: "high" });
return script._warmupEl;
},
load(cb) {
if (script.status === "removed")
return loadPromise;
script._triggerAbortControllers?.forEach((ac) => ac.abort());
script._triggerAbortControllers?.clear();
script._triggerPromises = [];
if (!script.entry) {
syncStatus("loading");
const defaults = {
defer: true,
fetchpriority: "low"
};
if (input.src && (input.src.startsWith("http") || input.src.startsWith("//"))) {
defaults.crossorigin = "anonymous";
defaults.referrerpolicy = "no-referrer";
}
script.entry = head.push({
script: [{ ...defaults, ...input }]
}, options);
}
if (cb)
_registerCb("loaded", cb);
return loadPromise;
},
onLoaded(cb, options2) {
return _registerCb("loaded", cb, options2);
},
onError(cb, options2) {
return _registerCb("error", cb, options2);
},
setupTriggerHandler(trigger) {
if (script.status !== "awaitingLoad") {
return;
}
if ((typeof trigger === "undefined" || trigger === "client") && !head.ssr || trigger === "server") {
script.load();
} else if (trigger instanceof Promise) {
if (head.ssr) {
return;
}
const abortController = new AbortController();
script._triggerAbortControllers = script._triggerAbortControllers || /* @__PURE__ */ new Set();
script._triggerAbortControllers.add(abortController);
const abortPromise = new Promise((resolve) => {
abortController.signal.addEventListener("abort", () => {
script._triggerAbortControllers?.delete(abortController);
resolve();
});
});
script._triggerAbortController = abortController;
script._triggerPromises = script._triggerPromises || [];
const triggerPromise = Promise.race([
trigger.then((v) => typeof v === "undefined" || v ? script.load : void 0),
abortPromise
]).catch(() => {
}).then((res) => {
res?.();
}).finally(() => {
script._triggerAbortControllers?.delete(abortController);
const idx = script._triggerPromises?.indexOf(triggerPromise) ?? -1;
if (idx !== -1)
script._triggerPromises?.splice(idx, 1);
});
script._triggerPromises.push(triggerPromise);
} else if (typeof trigger === "function") {
trigger(script.load);
}
},
_cbs
};
loadPromise.then((api) => {
if (api !== false) {
script.instance = api;
_cbs.loaded?.forEach((cb) => cb(api));
_cbs.loaded = null;
} else {
if (script.status === "error")
_cbs.error?.forEach((cb) => cb());
_cbs.loaded = null;
_cbs.error = null;
}
});
const hookCtx = { script };
script.setupTriggerHandler(options.trigger);
if (options.use) {
const { proxy, resolve } = createScriptProxy(head.ssr ? {} : options.use() || {});
script.proxy = proxy;
script.onLoaded(resolve);
}
if (!options.warmupStrategy && (typeof options.trigger === "undefined" || options.trigger === "client")) {
options.warmupStrategy = "preload";
}
if (options.warmupStrategy) {
script.warmup(options.warmupStrategy);
}
scripts[id] = script;
return script;
}
export { resolveScriptKey as r, useScript as u };