From 4cb4a46def100cfbab31751f0c6d96b689facc8b Mon Sep 17 00:00:00 2001 From: ssbg04 Date: Fri, 23 Oct 2026 19:53:38 +0800 Subject: [PATCH] fix: configure Google Ads for Vercel --- README.md | 2 +- index.html | 1 - public/_headers | 2 +- src/components/AdSlot.tsx | 16 ++++++++++++---- src/main.tsx | 10 ++++++++++ vercel.json | 2 +- 6 files changed, 25 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b16693d..9c29f1c 100644 --- a/README.md +++ b/README.md @@ -27,4 +27,4 @@ VITE_ADSENSE_CLIENT=ca-pub-XXXXXXXXXXXXXXXX VITE_ADSENSE_SLOT=XXXXXXXXXX ``` -Add the same values to a local `.env.local` file when testing. The AdSense script is loaded globally, while ad slots render only when both values are present. Use the exact publisher and slot IDs from AdSense; do not use guessed or test IDs in production. +Add the same values to a local `.env.local` file when testing. For Vercel, open **Project Settings → Environment Variables**, add both variables for **Production**, **Preview**, and **Development** as needed, then redeploy. Because these are `VITE_` variables, Vite injects them at build time; changing them requires a new deployment. The AdSense script and ad slots render only when both values are present. Use the exact publisher and slot IDs from AdSense; do not use guessed or test IDs in production. diff --git a/index.html b/index.html index 1a80f6b..4df03aa 100644 --- a/index.html +++ b/index.html @@ -33,7 +33,6 @@ - diff --git a/public/_headers b/public/_headers index fd3b74e..3d55d4b 100644 --- a/public/_headers +++ b/public/_headers @@ -3,4 +3,4 @@ X-Frame-Options: DENY Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: camera=(), microphone=(), geolocation=() - Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://pagead2.googlesyndication.com https://googleads.g.doubleclick.net https://ep2.adtrafficquality.google https://media.ethicalads.io blob:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: blob: https:; media-src 'self' data: blob: https:; connect-src 'self' https: blob: data:; frame-src 'self' https://googleads.g.doubleclick.net https://tpc.googlesyndication.com; worker-src 'self' blob:; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; + Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://pagead2.googlesyndication.com https://googleads.g.doubleclick.net https://ep2.adtrafficquality.google blob:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: blob: https:; media-src 'self' data: blob: https:; connect-src 'self' https: blob: data:; frame-src 'self' https://googleads.g.doubleclick.net https://tpc.googlesyndication.com https://www.google.com; worker-src 'self' blob:; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; diff --git a/src/components/AdSlot.tsx b/src/components/AdSlot.tsx index 6f27676..e02f6c4 100644 --- a/src/components/AdSlot.tsx +++ b/src/components/AdSlot.tsx @@ -26,10 +26,18 @@ export const AdSlot: React.FC = ({ placement, className = '' }) => useEffect(() => { if (!canRenderAd || !adRef.current || typeof window === 'undefined') return; - try { - (window.adsbygoogle = window.adsbygoogle || []).push({}); - } catch { - // Ad blockers and unapproved accounts can prevent the ad request. + const pushAd = () => { + try { + (window.adsbygoogle = window.adsbygoogle || []).push({}); + } catch { + return; + } + }; + + if (document.querySelector('script[data-adsense-loader]')) { + pushAd(); + } else { + window.setTimeout(pushAd, 250); } }, [canRenderAd]); diff --git a/src/main.tsx b/src/main.tsx index 5252e9d..fe3c053 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -3,6 +3,16 @@ import { createRoot } from 'react-dom/client'; import './index.css'; import App from './App.tsx'; +const adsenseClient = import.meta.env.VITE_ADSENSE_CLIENT; +if (adsenseClient && typeof document !== 'undefined' && !document.querySelector('script[data-adsense-loader]')) { + const script = document.createElement('script'); + script.async = true; + script.src = `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=${encodeURIComponent(adsenseClient)}`; + script.crossOrigin = 'anonymous'; + script.dataset.adsenseLoader = 'true'; + document.head.appendChild(script); +} + createRoot(document.getElementById('root')!).render( diff --git a/vercel.json b/vercel.json index 6e48b2a..1ff9bed 100644 --- a/vercel.json +++ b/vercel.json @@ -21,7 +21,7 @@ }, { "key": "Content-Security-Policy-Report-Only", - "value": "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://media.ethicalads.io blob:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: blob: https:; media-src 'self' data: blob:; connect-src 'self' https: blob: data:; worker-src 'self' blob:; object-src 'none'; frame-ancestors 'none'; base-uri 'self';" + "value": "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://pagead2.googlesyndication.com https://googleads.g.doubleclick.net https://ep2.adtrafficquality.google blob:; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: blob: https:; media-src 'self' data: blob: https:; connect-src 'self' https: blob: data:; frame-src 'self' https://googleads.g.doubleclick.net https://tpc.googlesyndication.com https://www.google.com; worker-src 'self' blob:; object-src 'none'; frame-ancestors 'none'; base-uri 'self';" } ] }