import type { AdSensePushCommand } from "./types.js"; const SCRIPT_MARKER = "adsbygoogle.js"; let scriptPromise: Promise | null = null; let scriptClient: string | null = null; function findExistingScript(adClient: string): HTMLScriptElement | null { for (const el of Array.from(document.scripts)) { if (el.src.includes(SCRIPT_MARKER) && el.src.includes(adClient)) { return el; } } return null; } /** * 加载 Google AdSense 官方脚本(幂等)。 * - 仅浏览器环境生效,SSR 中为 no-op * - 同一 adClient 复用同一 Promise;已在页面中的脚本会被识别并跳过 */ export function loadAdSense(adClient: string): Promise { if (typeof document === "undefined") { return Promise.resolve(); } if (scriptPromise) { if (scriptClient === adClient) { return scriptPromise; } return Promise.reject( new Error( `[adsense] 脚本已按 client=${scriptClient} 加载,不支持同时加载多个发布商 ID`, ), ); } const existing = findExistingScript(adClient); if (existing) { scriptClient = adClient; scriptPromise = Promise.resolve(); return scriptPromise; } scriptClient = adClient; scriptPromise = new Promise((resolve, reject) => { const script = document.createElement("script"); script.async = true; script.crossOrigin = "anonymous"; script.src = `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${encodeURIComponent(adClient)}`; script.onload = () => resolve(); script.onerror = () => { // 失败必须重置状态,否则后续调用会一直复用 rejected Promise 无法重试 scriptPromise = null; scriptClient = null; script.remove(); reject(new Error("[adsense] AdSense 脚本加载失败")); }; document.head.appendChild(script); }); return scriptPromise; } /** 向队列 push 一条命令,触发对已挂载 的渲染。 */ export function pushAdSense(command: AdSensePushCommand = {}): void { if (typeof window === "undefined") { return; } window.adsbygoogle ??= []; window.adsbygoogle.push(command); }