fix: Pexels image domain + ConsentInit'i statik script src'e taşı

İki sorun düzeltildi:

1) next.config.ts'e images.pexels.com (+ unsplash) eklendi
   - Mevcut 6 referans projesinde Pexels görsel URL'leri var
   - 'Invalid src prop on next/image' hatası giderildi
   - images.unsplash.com da eklendi (gelecekte kullanım için)

2) ConsentInit artık /public/consent-default.js'i src ile yüklüyor
   - React 19 + Next.js 16'da inline <script>{code}</script> ve
     <script dangerouslySetInnerHTML> her ikisi de 'Encountered a script
     tag while rendering React component' warning'i üretiyor
   - Statik dosya + <script src> pattern'i React'ın temiz şekilde
     kabul ettiği yöntem — warning yok, davranış aynı
   - GTM de aynı şekilde async src kullanıyor (önceki inline snippet
     yerine direkt GTM URL'i)
   - Consent default hala synchronous (script src defer/async olmadan)
     — gtag('consent','default') hiçbir analytics yüklenmeden çalışır
   - noscript iframe fallback korundu
This commit is contained in:
Ege Can Komur
2026-05-20 18:53:55 +03:00
parent 69f0c857ec
commit 8b4129c233
3 changed files with 30 additions and 34 deletions
+13 -34
View File
@@ -1,44 +1,23 @@
/**
* Google Consent Mode v2 — defaults set to "denied" before any tag loads.
* After the user makes a choice, CookieBanner calls gtag('consent','update', ...).
* Google Consent Mode v2 — default consent state denied'da.
* Consent default ayarı `/public/consent-default.js`'den senkron yüklenir
* (script src ile — React'ın inline script warning'inden kaçınmak için).
*
* Next.js 16 / React 19'da `next/script` inline scripts ile sorunlu olduğu için
* doğrudan <script dangerouslySetInnerHTML> kullanıyoruz. Script senkron olarak
* HTML parse edildiği anda çalışır — gtag('consent','default') hiçbir analytics
* scripti yüklenmeden önce kaydedilir.
* GTM script'i sadece gtm_id varsa yüklenir, aynı src pattern'i kullanır.
*/
export function ConsentInit({ gtmId }: { gtmId?: string | null }) {
const defaultConsent = `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
window.gtag = gtag;
gtag('consent', 'default', {
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
analytics_storage: 'denied',
functionality_storage: 'granted',
personalization_storage: 'denied',
security_storage: 'granted',
wait_for_update: 500,
});
`;
const gtmSnippet = gtmId
? `
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});
var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';
j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${gtmId}');
`
: null;
return (
<>
<script dangerouslySetInnerHTML={{ __html: defaultConsent }} />
{gtmSnippet && (
{/* Default consent — synchronous, runs before any other JS */}
<script src="/consent-default.js" />
{/* GTM */}
{gtmId && (
<>
<script dangerouslySetInnerHTML={{ __html: gtmSnippet }} />
<script
async
src={`https://www.googletagmanager.com/gtm.js?id=${gtmId}`}
/>
<noscript>
<iframe
src={`https://www.googletagmanager.com/ns.html?id=${gtmId}`}