71 lines
2.3 KiB
TypeScript
71 lines
2.3 KiB
TypeScript
import type { AdSensePushCommand } from "./types.js";
|
||
|
||
const SCRIPT_MARKER = "adsbygoogle.js";
|
||
|
||
let scriptPromise: Promise<void> | 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<void> {
|
||
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<void>((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 一条命令,触发对已挂载 <ins class="adsbygoogle"> 的渲染。 */
|
||
export function pushAdSense(command: AdSensePushCommand = {}): void {
|
||
if (typeof window === "undefined") {
|
||
return;
|
||
}
|
||
window.adsbygoogle ??= [];
|
||
window.adsbygoogle.push(command);
|
||
}
|