Persetujuan Cookie untuk Next.js, Gatsby, dan Situs Statis: Panduan Integrasi untuk Developer
Masalah Persetujuan di Situs Statis
Framework JavaScript modern seperti Next.js, Gatsby, dan Nuxt.js memperkenalkan pergeseran paradigma dalam cara halaman web dibangun dan dikirimkan. Halaman di-prerender saat build atau di server, lalu dihidrasi di sisi klien. Ini menciptakan tantangan unik untuk persetujuan cookie: banner persetujuan harus siap sebelum skrip pelacakan apa pun dijalankan, tetapi halaman itu sendiri mungkin sudah dirender dan di-cache di edge.
CMP tradisional dirancang untuk halaman PHP yang dirender di server atau halaman HTML sederhana di mana dokumen dimuat secara linear dari atas ke bawah. Di dunia framework dengan code splitting, lazy loading, dan streaming server-side rendering, asumsi-asumsi tersebut runtuh. Mengelola persetujuan dengan benar di lingkungan ini memerlukan pemahaman terhadap pipeline rendering.
Mengapa Timing Jauh Lebih Penting dari yang Anda Kira
Di halaman HTML standar, menempatkan skrip CMP di dalam <head> sebelum skrip lain cukup mudah. Di Next.js App Router atau Gatsby, situasinya lebih kompleks:
- HTML yang sudah diprerender tiba lebih dulu: Browser menerima HTML lengkap dari CDN atau server. Jika ada skrip inline atau tag pihak ketiga yang disematkan di HTML tersebut, skrip itu bisa dieksekusi sebelum logika persetujuan Anda dimuat.
- Celah hidrasi: Hidrasi React terjadi setelah HTML dipaint. Jika komponen persetujuan Anda adalah komponen React, ia belum ada dalam keadaan fungsional sampai hidrasi selesai. Selama celah ini, tag Google atau skrip analitik bisa berjalan tanpa persetujuan.
- Komplikasi cache di edge: Jika Anda menggunakan ISR (Incremental Static Regeneration) atau edge function, HTML akan di-cache. Anda tidak bisa menyuntikkan logika yang bergantung pada persetujuan ke dalam HTML yang sudah di-cache tanpa mekanisme sisi klien.
Prinsip intinya adalah: persetujuan harus ditegakkan di level skrip, bukan di level komponen. Komponen React yang merender banner persetujuan datang terlambat jika baru menjadi interaktif setelah hidrasi.
Integrasi Next.js App Router
Next.js 13+ dengan App Router memperkenalkan cara baru untuk menangani skrip. Berikut pendekatan yang direkomendasikan untuk integrasi persetujuan:
Langkah 1: Muat Skrip CMP di Root Layout
Gunakan komponen Script Next.js dengan strategi beforeInteractive di layout.tsx root Anda. Ini memberi tahu Next.js untuk menyuntikkan skrip ke dokumen HTML awal, sebelum hidrasi dimulai:
Strategi beforeInteractive sangat krusial. Strategi bawaan afterInteractive memuat skrip setelah hidrasi, yang terlalu terlambat untuk persetujuan. Dengan beforeInteractive, skrip CMP disertakan di HTML yang dirender di server dan dijalankan saat halaman dimuat.
Langkah 2: Setel Default Persetujuan Sebelum Tag Google
Sebelum snippet Google Tag Manager atau gtag.js Anda, sertakan skrip inline yang menetapkan status persetujuan default. Ini memastikan bahwa bahkan jika GTM dimuat sebelum banner CMP muncul, GTM tetap menghormati default yang ditolak:
Skrip inline ini harus ditempatkan di dalam <head> layout root Anda, sebelum skrip CMP dan GTM. Di Next.js, Anda dapat menggunakan tag <script> biasa di dalam elemen <head> layout untuk tujuan ini.
Langkah 3: Tangani Perubahan Rute
Pada navigasi single-page application, skrip CMP dimuat sekali tetapi perubahan rute tidak memicu reload halaman penuh. CMP Anda harus bertahan di seluruh navigasi sisi klien. FlexyConsent menangani ini secara otomatis — setelah dimuat, ia tetap aktif di semua perubahan rute tanpa inisialisasi ulang.
Integrasi Next.js Pages Router
Untuk proyek yang masih menggunakan Pages Router, pendekatannya mirip tetapi menggunakan _document.tsx alih-alih root layout. Tempatkan skrip CMP di komponen <Head> dari custom Document class Anda. Strategi beforeInteractive bekerja dengan cara yang sama di Pages Router.
Perbedaan utamanya adalah _document.tsx hanya dirender di server, sehingga logika persetujuan apa pun di sini dijamin ada di payload HTML awal.
Integrasi Situs Statis Gatsby
Gatsby menghasilkan HTML statis sepenuhnya saat build. Tidak ada server-side rendering saat request, yang menyederhanakan beberapa aspek tetapi mempersulit yang lain:
- Gunakan
gatsby-ssr.tsxuntuk menyuntikkan skrip CMP ke dalam<head>setiap halaman. APIonRenderBodymemungkinkan Anda menambahkan skrip ke head yang akan hadir di setiap file HTML statis. - Hindari plugin Gatsby yang memuat persetujuan secara lazy: Beberapa plugin komunitas membungkus persetujuan dalam komponen React yang hanya mount setelah hidrasi. Ini menciptakan celah timing yang dibahas sebelumnya.
- Tempatkan default persetujuan secara inline: Gunakan
setHeadComponentsdigatsby-ssr.tsxuntuk menambahkan skrip inline yang mengatur status persetujuan default. Skrip ini akan berada di HTML statis dan dieksekusi segera.
Pendekatan build-time Gatsby berarti setiap file HTML di CDN Anda akan menyertakan skrip persetujuan. Ini sebenarnya ideal — tidak ada logika server yang bisa gagal atau salah cache.
Pertimbangan Nuxt.js
Nuxt.js (berbasis Vue) memiliki polanya sendiri. Di Nuxt 3, gunakan composable useHead atau konfigurasi app head di nuxt.config.ts untuk menambahkan skrip CMP secara global. Nuxt mendukung opsi body: false (yang menempatkan skrip di head) dan atribut async untuk pemuatan non-blocking.
Untuk mode server-side rendering Nuxt, prinsip yang sama berlaku: skrip CMP harus ada di respons HTML awal, bukan disuntikkan secara dinamis oleh komponen Vue setelah mount.
Menghindari Layout Shift
Banner persetujuan terkenal menyebabkan Cumulative Layout Shift (CLS), salah satu Core Web Vitals yang memengaruhi peringkat SEO. Ketika banner muncul setelah halaman dirender, ia mendorong konten ke bawah atau menimpanya secara tak terduga.
Strategi untuk meminimalkan CLS dari banner persetujuan:
- Gunakan banner di posisi bawah: Banner di bagian bawah viewport tidak menggeser konten halaman. Ini adalah pendekatan yang paling ramah CLS.
- Cadangkan ruang: Jika Anda harus menggunakan banner di bagian atas, cadangkan ruang vertikal di CSS sehingga layout halaman sudah memperhitungkan banner sebelum dirender.
- Hindari modal overlay saat load: Dinding persetujuan layar penuh yang muncul setelah halaman dirender menyebabkan ketidakstabilan layout yang terasa. Jika Anda memerlukan wall, render sebagai bagian dari state awal halaman.
- Muat CMP secara sinkron di head: Saat CMP dimuat sebagai skrip yang memblokir render di head, banner dapat muncul sebagai bagian dari paint awal alih-alih muncul belakangan.
Pendekatan Agnostik Framework dari FlexyConsent
FlexyConsent dirancang untuk bekerja dengan framework apa pun — atau tanpa framework sama sekali — dengan beroperasi di level skrip, bukan level komponen. Berikut alasan mengapa ini penting:
- Satu tag skrip async tunggal: Hanya diperlukan satu tag
<script>di<head>. Tidak ada paket npm yang perlu diinstal, tidak ada wrapper khusus framework, tidak ada konfigurasi build. - Default persetujuan dijalankan segera: Skrip menetapkan default Consent Mode V2 sebagai aksi pertamanya, sebelum callback atau manipulasi DOM apa pun. Ini berarti tag Google menghormati persetujuan sejak milidetik pertama.
- Tidak bergantung pada DOM: Logika persetujuan tidak menunggu React, Vue, atau Svelte untuk hidrasi. Ia beroperasi secara independen dari lifecycle framework.
- Bekerja dengan SSG, SSR, ISR, dan CSR: Karena berupa skrip biasa, ia berfungsi identik apakah halaman dihasilkan secara statis, dirender di server, diregenerasi secara inkremental, atau dirender di sisi klien.
Tips untuk developer: Tes paling sederhana untuk memastikan integrasi CMP yang benar adalah membuka tab Network di browser Anda, filter berdasarkan domain Google, lalu reload halaman. Tidak boleh ada request ke Google yang berjalan sebelum perintah default persetujuan muncul di console. Jika ada, berarti CMP Anda dimuat terlalu lambat.
Paket gratis FlexyConsent mendukung pageview tanpa batas dan bekerja dengan Next.js, Gatsby, Nuxt, Astro, SvelteKit, Remix, dan HTML biasa. Integrasinya sama di semuanya: satu tag skrip, ditempatkan dengan benar.