Dari Edit layout.tsx Jadi Satu Request PUT
Ganti script GSC atau analytics nggak perlu redeploy lagi: modul settings di API dengan whitelist kunci, GET publik, dan admin ber-API-key.
Dulu tiap kali butuh ubah script di header situs, urutannya begini: buka layout.tsx, tempel snippet, commit, push, tunggu deploy selesai. Semua itu cuma buat nambahin satu tag verifikasi Google Search Console. Kerjaannya lima menit, tapi nunggunnya bisa belasan menit.
Commit terakhir soal ini, 62a2d4b, ngubah urutan itu jadi satu request. PUT ke endpoint settings, isi snippet-nya, selesai. Deploy udah nggak terlibat sama sekali.
Dugaan pertama yang meleset
Awalnya saya kira urusan script pihak ketiga tinggal pakai next/script dengan afterInteractive. Toh itu default-nya, dan buat analytics biasa emang cukup [1]. Script jalan tiap halaman dibuka, hydration nggak diganggu.
Ternyata nggak semua snippet boleh nunggu hydration. Dokumentasi Next.js bilang beforeInteractive dieksekusi sebelum kode Next.js apa pun di-load dan sebelum hydration terjadi, komponennya wajib ditaruh di root layout, dan selalu di-inject ke head HTML [1]. Dugaan "satu mode buat semua" langsung gugur. [1]
Soal verifikasi GSC sendiri, saya sempat mikir harus tempel meta tag manual di head. Ternyata App Router punya jalur resmi: objek metadata statis dengan metadata.verification.google, dan Next.js otomatis me-render tag meta google-site-verification dari situ [2]. Metadata statis didefinisikan lewat objek metadata, bukan generateMetadata, karena nggak tergantung info request [2]. Nggak perlu nyentuh template head.
Modul settings: satu pintu, tiga kunci
Di sisi API (FastAPI, arsitektur DDD), saya bikin modul settings dengan whitelist tiga kunci: google_site_verification, head_snippet, dan footer_snippet. Whitelist ini penting. Tanpa itu, endpoint settings jadi pintu masuk buat sembarang konten yang nanti di-inject ke head semua halaman, dan itu lubang keamanan klasik.
Endpoint-nya dua rasa. GET /settings/site terbuka buat publik tanpa API key, karena frontend butuh baca snippet tiap render. Ngubah data cuma lewat PUT atau DELETE admin yang wajib bawa header API key. Pola baca-publik-tulis-terlindungi standar, tapi tetap harus ditegakkan di kode, bukan cuma di kepala.
Bentuknya sependek ini, ambil apa adanya dari commit:
import Script from "next/script";
import { fetchSiteSettings } from "@/services/settings-service";
export default async function SiteHeadSnippet() {
const settings = await fetchSiteSettings();
if (!settings.head_snippet) return null;
return (
<Script
id="site-head-snippet"
strategy="beforeInteractive"
dangerouslySetInnerHTML={{ __html: settings.head_snippet }}
/>
);
}
Frontend-nya dua komponen kecil di root layout. SiteHeadSnippet membungkus head_snippet dengan beforeInteractive, karena isinya harus nyusul lebih awal [1]. SiteFooterSnippet membungkus footer_snippet dengan afterInteractive, mode default yang aman buat script yang nggak butuh kecepatan [1].
Test-nya 7 buah, semua jalan di sqlite in-memory, cukup buat mastiin whitelist dan permission-nya nggak balik arah. Total 697 insertions di 23 file [5].
Kenapa keputusan ini masuk akal
Perubahan settings harus langsung kelihatan. Kalo frontend baca settings tiap request tanpa cache, tiap render nambah satu query ke API. Makanya ada Redis tag cache dengan invalidation tiap ada perubahan [4]. Cache invalidation intinya buang data cache yang udah nggak valid biar konten lama nggak kebawa [4]. Tag-nya bikin pembuangan itu presisi: invalidate satu tag, semua kunci terkait ikut ke-flush.
Alasan kehati-hatian di sisi tulis juga jelas. Verified owner itu permission tertinggi atas properti situs di Search Console [3], jadi pintu yang bisa ngganti script verifikasi emang nggak boleh longgar. Satu header API key salah, request ditolak. Enak malah, gitu.
Opini saya sekarang tegas: default buat script pihak ketiga ya afterInteractive, titik. beforeInteractive cuma buat yang memang wajib nyusul sebelum kode Next.js jalan [1]. Semua yang lain saya taruh di footer snippet dan biarin hydration selesai dulu.
Yang paling kerasa sih bukan soal cepat. Tapi layout.tsx saya nggak tersentuh lagi buat urusan snippet, dan itu artinya nggak ada lagi deploy cuma gara-gara satu tag meta. Kapan butuh kunci keempat di whitelist, tinggal tambahin.
Sumber yang saya pakai
[1] https://nextjs.org/docs/app/api-reference/components/script
[2] https://nextjs.org/docs/app/api-reference/functions/generate-metadata
[3] https://support.google.com/webmasters/answer/9008080?hl=en
[4] https://redis.io/glossary/cache-invalidation
[5] https://github.com/didiet86/my-apps/commit/62a2d4b1632dbd54d0784763695a1076e7da03b4