ქუქი-ფაილებზე თანხმობა Next.js‑ში, Gatsby‑ში და სტატიკურ საიტებზე: დეველოპერის ინტეგრაციის გზამკვლევი
თანხმობის პრობლემა სტატიკურ საიტებზე
თანამედროვე JavaScript ჩარჩოებმა, როგორიცაა Next.js, Gatsby და Nuxt.js, რადიკალურად შეცვალეს, თუ როგორ იქმნება და მიეწოდება ვებგვერდები. გვერდები წინასწარ რენდერდება build-ის დროს ან სერვერზე, შემდეგ კი კლიენტზე ხდება მათი ჰიდრაცია. ეს ქმნის უნიკალურ გამოწვევას ქუქი-ფაილებზე თანხმობისთვის: თანხმობის ბანერი მზად უნდა იყოს მანამდე, სანამ რაიმე თრექინგ-სკრიპტი შესრულდება, მაგრამ თავად გვერდი შეიძლება უკვე იყოს დარენდერებული და edge-ზე დაკეშილი.
ტრადიციული CMP-ები შექმნილი იყო სერვერზე რენდერებული PHP ან მარტივი HTML გვერდებისთვის, სადაც დოკუმენტი ზედა ნაწილიდან ქვემოთ ხაზობრივად იტვირთება. ჩარჩოების სამყაროში, სადაც გვაქვს code splitting, lazy loading და streaming server-side rendering, ეს დაშვებები იშლება. ამ გარემოებში თანხმობის სწორად დაყენება მოითხოვს რენდერინგის পাইპლაინის გაგებას.
რატომ არის დროის ფაქტორი უფრო მნიშვნელოვანი, ვიდრე გგონიათ
სტანდარტულ HTML გვერდზე CMP-სკრიპტის განთავსება <head>-ში სხვა სკრიპტებამდე მარტივია. Next.js App Router-სა და Gatsby-ში სიტუაცია უფრო რთულია:
- პირველად მოდის წინასწარ დარენდერებული HTML: ბრაუზერი CDN-იდან ან სერვერიდან იღებს სრულ HTML-ს. თუ ამ HTML-ში ჩაშენებულია inline-სკრიპტები ან მესამე მხარის ტეგები, ისინი შეიძლება შესრულდეს მანამდე, სანამ თქვენი თანხმობის ლოგიკა ჩაიტვირთება.
- ჰიდრაციის შუალედი: React-ის ჰიდრაცია ხდება მას შემდეგ, რაც HTML დაიხატება. თუ ���ქვენი თანხმობის კომპონენტი React კომპონენტია, ის ფუნქციურ მდგომარეობაში მხოლოდ ჰიდრაციის დასრულების შემდეგ გადადის. ამ შუალედში Google-ის ტეგები ან ანალიტიკის სკრიპტები შეიძლება თანხმობის გარეშე გაეშვას.
- Edge-ქეშირების სირთულეები: თუ იყენებთ ISR-ს (Incremental Static Regeneration) ან edge-ფუნქციებს, HTML დაკეშილია. ქეშირებულ HTML-ში თანხმობაზე დამოკიდებული ლოგიკის დინამიურად ჩასმა შეუძლებელია კლიენტის მხარის მექანიზმის გარეშე.
ძირითადი პრინციპი ასეთია: თანხმობა უნდა დადგინდეს სკრიპტის დონეზე და არა კომპონენტის დონეზე. React კ��მპონენტი, რომელიც რენდერავს თანხმობის ბანერს, უკვე გვიანია, თუ ის მხოლოდ ჰიდრაციის შემდეგ ხდება ინტერაქტიული.
Next.js App Router-ის ინტეგრაცია
Next.js 13+ App Router-ით შემოიტანა სკრიპტების დამუშავების ახალი გზა. აი რეკომენდებული მიდგომა თანხმობის ინტეგრაციისთვის:
ნაბიჯი 1: ჩატვირთეთ CMP-სკრიპტი root layout-ში
გამოიყენეთ Next.js-ის Script კომპონენტი beforeInteractive სტრატეგიით თქვენს root layout.tsx-ში. ეს ეუბნება Next.js-ს, რომ სკრიპტი ჩასვას საწყის HTML დოკუმენტში ჰიდრაციის დაწყებამდე:
beforeInteractive სტრატეგია კრიტიკულია. ნაგულისხმევი afterInteractive სტრა���ეგია სკრიპტებს ჰიდრაციის შემდეგ ტვირთავს, რაც თანხმობისთვის გვიანია. beforeInteractive-ით CMP-სკრიპტი შედის სერვერზე რენდერებულ HTML-ში და სრულდება გვერდის ჩატვირთვისას.
ნაბიჯი 2: დააყენეთ ნაგულისხმევი თანხმობა Google-ის ტეგებამდე
თქვენი Google Tag Manager-ის ან gtag.js-ის სნიპეტამდე ჩასვით inline-სკრიპტი, რომელიც ადგენს ნაგულისხმევ თანხმობის მდგომარეობებს. ეს უზრუნველყოფს, რომ თუნდაც GTM ჩაიტვირთოს CMP ბანერის გამოჩენამდე, ის მაინც გაითვალისწინებს უარყოფით ნაგულისხმევებს:
ეს inline-სკრიპტი უნდა იყოს განთავსებული root layout-ის <head>-ში, CMP და GTM სკრიპტებამდე. Next.js-ში ამისთვის შეგიძლიათ გამოიყენოთ ჩვეულებრივი <script> ტეგი layout-ის <head> ელემენტში.
ნაბიჯი 3: დაამუშავეთ მარშრუტების ცვლილებები
Single-page აპლიკაციის ნავიგაციაში CMP-სკრიპტი ერთხელ იტვირთება, მაგრამ მარშრუტის ცვლილებები სრულ გვერდის გადატვირთვას არ იწვევს. თქვენი CMP უნდა შენარჩუნდეს კლიენტის მხარის ნავიგაციებს შორის. FlexyConsent ამას ავტომატურად აკეთებს — ერთხელ ჩატვირთვის შემდეგ ის აქტიური რჩება ყველა მარშრუტის ცვლილებაზე ხელახალი ინიციალიზაციის გარეშე.
Next.js Pages Router-ის ინტეგრაცია
პროექტებისთვის, რომლებიც ჯერ კიდევ იყენებენ Pages Router-ს, მიდგომა მსგავსია, მაგრამ root layout-ის ნაცვლად გამოიყენება _document.tsx. CMP-სკრიპტი განათავსეთ თქვენი custom Document კლასის <Head> კომპონენტში. beforeInteractive სტრატეგია Pages Router-ში ანალოგიურად მუშაობს.
ძირითადი განსხვავება ის არის, რომ _document.tsx მხოლოდ სერვერზე რენდერდება, ამიტომ აქ არსებული ნებისმიერი თანხმობის ლოგიკა გარანტირებულად შევა საწყის HTML payload-ში.
Gatsby-ს სტატიკური საიტის ინტეგრაცია
Gatsby build-ის დროს ქმნის სრულად სტატიკურ HTML-ს. მოთხოვნის მომენტში სერვერზე რენდერინგი არ ხდება, რაც ზოგ რამეს ამარტივებს, მაგრამ სხვას ართულებს:
- გამოიყენეთ
gatsby-ssr.tsx, რათა ჩასვათ CMP-სკრიპტი თითოეული გვერდის<head>-ში.onRenderBodyAPI საშუალებას გაძლევთ დაამატოთ head-სკრიპტები, რომლებიც ყველა სტატიკურ HTML ფაილში იქნება. - თავი აარიდეთ Gatsby-ს პლაგინებს, რომლებიც თანხმობას lazy-load-ით ტვირთავენ: ზოგიერთ community-პლაგინს თანხმობა React კომპონენტში აქვს გახვეული, რომელიც მხოლოდ ჰიდრაციის შემდეგ მონტირდება. ეს ქმნის ზემოთ განხილულ დროით შუალედს.
- განათავსეთ ნაგულისხმევი თანხმობა inline-სკრიპტით: გამოიყენეთ
setHeadComponentsgatsby-ssr.tsx-ში, რათა დაამატოთ inline-სკრიპტი, რომელიც ადგენს ნაგულისხმევ თანხმობის მდგომარეობებს. ეს სკრიპტი იქნება სტატიკურ HTML-ში და დაუყოვნებლივ შესრულდება.
Gatsby-ს build-დროის მიდგომა ნიშნავს, რომ თქვენს CDN-ზე არსებულ ყველა HTML ფაილში იქნება თანხმობის სკრიპტი. ეს რეალურად იდეალურია — არ არსებობს სერვერის ლოგიკა, რომელიც შეიძლება ჩავარდეს ან არასწორად დაკეშდეს.
Nuxt.js-ის თავისებურებები
Nuxt.js (Vue-ზე დაფუძნებული) თავის ნიმუშებს იყენებს. Nuxt 3-ში გამოიყენეთ useHead composable ან nuxt.config.ts-ის app head კონფიგურაცია CMP-სკრიპტის გლობალურად დასამატებლად. Nuxt მხარს უჭერს პარამეტრს body: false (რომელიც სკრიპტებს head-ში ათავსებს) და async ატრიბუტს არაბლოკირებადი ჩატვირთვისთვის.
Nuxt-ის server-side rendering რეჟიმისთვის იგივე პრინციპი მოქმედებს: CMP-სკრიპტი უნდა იყოს საწყის HTML პასუხში და არა Vue კომპონენტის მიერ mount-ის შემდეგ დინამიურად ჩასმული.
Layout Shift-ის თავიდან აცილება
თანხმობის ბანერები ცნობილია, რომ იწვევენ Cumulative Layout Shift (CLS)-ს — Core Web Vital მეტრიკას, რომელიც SEO რეიტინგებზე მოქმედებს. როდესაც ბანერი ჩნდება გვერდის რენდერინგის შემდეგ, ის ქვემოთ სწევს კონტენტს ან მოულოდნელად ახვევს მას.
სტრატეგიები CLS-ის მინიმიზაციისთვის თანხმობის ბანერების შემთხვევაში:
- გამოიყენეთ ქვედა პოზიციაზე განთავსებული ბანერი: viewport-ის ქვედა ნაწილში განთავსებული ბანერები გვერდის კონტენტს არ წევს. ეს ყველაზე CLS-მეგობრული მიდგომაა.
- დარეზერვეთ სივრცე: თუ გჭირდებათ ზედა ბანერი, CSS-ში წინასწარ გამოყავით ვერტიკალური სივრცე, რათა გვერდის layout-მა ბანერი გაითვალისწინოს რენდერინგამდე.
- თავი აარიდეთ მოდალურ overlay-ს ჩატვირთვისას: სრულეკრანიანი consent wall-ები, რომლებიც გვერდის რენდერინგის შემდეგ ჩნდება, აღქმულ layout-ის არასტაბილურობას იწვევს. თუ wall აუცილებელია, ის საწყისი გვერდის მდგომარეობის ნაწილად უნდა დაირენდეროს.
- ჩატვირთეთ CMP head-ში სინქრონულად: როდესაც CMP head-ში render-blocking სკრიპტად იტვირთება, ბანერი შეიძლება საწყისი paint-ის ნაწილად გამოჩნდეს და არა მოგვიანებით „ამოხტეს“.
FlexyConsent-ის ჩარჩოებზე დამოუკიდებელი მიდგომა
FlexyConsent შექმნილია ისე, რომ იმუშაოს ნებისმიერ ჩარჩოსთან — ან საერთოდ ჩარჩოს გარეშე — კომპონენტის დონის ნაცვლად სკრიპტის დონეზე ოპერირებით. აი, რატომ არის ეს მნიშვნელოვანი:
- ერთი async script ტ���გი: საკმარისია ერთი
<script>ტეგი<head>-ში. არც npm პაკეტების დაყენებაა საჭირო, არც ჩარჩოზე სპეციფიკური wrapper-ები, არც build-კონფიგურაცია. - თანხმობის ნაგულისხმევები მყისიერად მუშაობს: სკრიპტი Consent Mode V2-ის ნაგულისხმევებს აყენებს პირველივე ქმედებად, ნებისმიერ callback-სა და DOM მანიპულაციამდე. ეს ნიშნავს, რომ Google-ის ტეგები თანხმობას პირველივე მილიწამიდან ითვალისწინებენ.
- DOM-ზე არ არის დამოკიდებული: თანხმობის ლოგიკა არ ელოდება React, Vue ან Svelte-ის ჰიდრაციას. ის ჩარჩოს lifecycle-ისგან დამოუკიდებლად მუშაობს.
- მუშაობს SSG, SSR, ISR და CSR რეჟიმებში: რადგან ეს უბრალო სკრიპტია, ის იდენტურად ფუნქციონირებს, მიუხედავად იმისა, სტატიკურად იყო თუ არა გვერდი გენერირებული, სერვერზე რენდერებული, ინკრემენტულად განახლებული თუ კლიენტის მხარეს რენდერებული.
დეველოპერის რჩევა: CMP-ის სწორი ინტეგრაციის ყველაზე მარტივი ტესტია ბრაუზერის Network ტაბის გახსნა, ფილტრი Google-ის დომენებზე და გვერდის გადატვირთვა. სანამ კონსოლში თანხმობის ნაგულისხმევი ბრძანება გამოჩნდება, არც ერთი Google მოთხოვნა არ უნდა გაეშვას. თუ გაეშვა, თქვენი CMP ძალიან გვიან იტვირთება.
FlexyConsent-ის უფასო გეგმა მხარს უჭერს შეუზღუდავ გვერდის ნახვებს და მუშაობს Next.js, Gatsby, Nuxt, Astro, SvelteKit, Remix და უბრალო HTML-თან. ინტეგრაცია ყველგან ერთნაირია: ერთი სწორად განთავსებული script ტეგი.