9
Utilitas, Logger, dan Environment
Tiga modul kecil di src/lib menyangga hampir seluruh komponen: cn yang menggabungkan class Tailwind, logger yang mencetak log bergaya INFO, dan env.ts yang memvalidasi variabel environment dengan zod. Rantai sakelar logger tidak berhenti di src/lib, karena nilai showLogger dihitung di src/constant/env.ts (src/constant/env.ts:1-61).
Katalog utilitas
| Berkas | Ekspor | Peran |
|---|---|---|
src/lib/utils.ts | cn | menggabungkan clsx dan twMerge menjadi satu className |
src/lib/logger.ts | logger (default) | membungkus console.log dengan gerbang showLogger |
src/lib/env.ts | efek samping envVariables.parse | memvalidasi process.env dengan skema zod |
src/constant/env.ts | isProd, isLocal, showLogger | menerjemahkan NODE_ENV dan NEXT_PUBLIC_SHOW_LOGGER menjadi boolean |
src/lib/helper.ts | getFromLocalStorage, getFromSessionStorage | pembacaan storage yang aman saat render server |
src/lib/og.ts | openGraph | menyusun URL gambar Open Graph |
cn: clsx untuk bentuk, twMerge untuk konflik
cn menerima ...inputs: ClassValue[] dari clsx, memanggil clsx(inputs), lalu menyerahkan hasilnya ke twMerge (src/lib/utils.ts:1-72). Pembagian tugasnya jelas: clsx meratakan string, array, dan objek kondisional menjadi satu string, sedangkan twMerge membuang utilitas Tailwind yang bertabrakan di kelompok yang sama.
graph LR
A["cn(...inputs: ClassValue[])"]
A --> B["clsx(inputs)<br/>meratakan string, array, objek"]
B --> C["twMerge(hasil clsx)<br/>menyelesaikan utility yang bertabrakan"]
C --> D["satu string className"]
style A fill:#f59e0b,color:#000
style B fill:#f59e0b,color:#000
style C fill:#8b5cf6,color:#fff
style D fill:#2d7d46,color:#fff
%% fig: Pipeline cn dari masukan sampai className final
%% desc: clsx meratakan bentuk masukan, twMerge membuang konflik utilitas Tailwind, keluarannya satu string className.Urutan argumen menentukan pemenang. Di Button, className diletakkan sebagai argumen terakhir setelah class dasar, array size, dan array variant, sehingga class dari pemanggil menimpa class bawaan (src/components/buttons/Button.tsx:48-993). Pola yang sama dipakai komponen link, NextImage, dan Skeleton; daftar pemakainya ada di Katalog Komponen Pratinjau.
showLogger sebagai gerbang logger
logger diekspor sebagai default dan menerima object: unknown serta comment?: string (src/lib/logger.ts:94). Baris pertama berkas mematikan aturan no-console supaya pemanggilan console.log lolos lint (src/lib/logger.ts:15). Gerbangnya berupa early return: if (!showLogger) return; (src/lib/logger.ts:9-196).
Saat sakelar menyala, console.log mencetak penanda %c ============== INFO LOG dengan warna #22D3EE, window.location.pathname bila kode berjalan di browser, komentar yang dioper, lalu objeknya (src/lib/logger.ts:12-187). Parameternya dirancang untuk snippet lg pada editor.
Nilai showLogger dihitung sekali saat modul dimuat: isLocal (dari NODE_ENV === 'development') membuatnya selalu true, sedangkan di luar development nilainya process.env.NEXT_PUBLIC_SHOW_LOGGER === 'true' (src/constant/env.ts:4-68). Dua konstanta pendampingnya, isProd dan isLocal, hanya membaca process.env.NODE_ENV (src/constant/env.ts:1-29).
⚠️ Di
developmentsakelar ini tidak bisa dimatikan lewat environment, karenaisLocalselalu menang. Di production nilainya hanya menyala bila string-nya persis"true".
Pada commit ini belum ada berkas yang memanggil logger; satu-satunya kemunculan logger( di repository adalah definisinya sendiri (src/lib/logger.ts:94).
src/lib/env.ts memvalidasi process.env
Berkas src/lib/env.ts diimpor murni untuk efek sampingnya dari src/app/page.tsx, yang berjalan sebagai client component (src/app/page.tsx:1-410). Begitu modul dievaluasi, envVariables.parse(process.env) langsung dijalankan (src/lib/env.ts:1311).
Skemanya hanya punya satu kunci, NEXT_PUBLIC_SHOW_LOGGER: z.enum(['true', 'false']).optional() (src/lib/env.ts:9-1112). Karena skema tidak memakai .strict(), variabel lain di process.env diabaikan. Setelah parse berhasil, declare global memperluas NodeJS.ProcessEnv dengan z.infer dari skema itu, sehingga process.env.NEXT_PUBLIC_SHOW_LOGGER bertipe 'true' | 'false' | undefined (src/lib/env.ts:15-1913).
Rantai lengkapnya, dari impor sampai pemanggilan logger, tampak pada diagram berikut.
sequenceDiagram
autonumber
participant Page as src/app/page.tsx
participant Env as src/lib/env.ts
participant Zod as skema zod
participant Proc as process.env
participant Const as src/constant/env.ts
participant Log as src/lib/logger.ts
Page->>Env: import '@/lib/env'
Env->>Proc: "envVariables.parse(process.env)"
Proc-->>Env: NEXT_PUBLIC_SHOW_LOGGER
Env->>Zod: "z.enum(['true', 'false']).optional()"
alt nilai tidak cocok skema
Zod-->>Page: ZodError saat modul dimuat
else valid atau tidak diset
Zod-->>Env: lolos validasi
end
Const->>Proc: "process.env.NODE_ENV"
Note over Const: "showLogger = isLocal ? true : NEXT_PUBLIC_SHOW_LOGGER === 'true'"
Log->>Const: "import { showLogger }"
Log->>Log: "if (!showLogger) return"
alt showLogger false
Note over Log: tidak ada output
else showLogger true
Log->>Log: "console.log('%c ============== INFO LOG', ...)"
end
%% fig: Alur pembacaan environment sampai pemanggilan logger
%% desc: Impor src/lib/env memvalidasi process.env dengan zod, src/constant/env.ts menurunkan showLogger, lalu logger memutuskan berhenti atau mencetak log.Variabel yang benar-benar dibaca kedua modul itu hanya dua.
| Variabel | Skema zod | Dibaca oleh | Efek |
|---|---|---|---|
NEXT_PUBLIC_SHOW_LOGGER | z.enum(['true', 'false']).optional() (src/lib/env.ts:9-1112) | showLogger | menyalakan log di luar development |
NODE_ENV | tidak divalidasi | isProd, isLocal (src/constant/env.ts:1-29) | menentukan apakah showLogger otomatis true |
.env.example mendaftarkan satu variabel contoh, NEXT_PUBLIC_SHOW_LOGGER="false", dengan instruksi menduplikasi berkas itu menjadi .env.local dan catatan agar nilainya tidak dipasang di environment deployment produksi (.env.example:1-614). Versi pustaka yang terlibat adalah clsx ^2.0.0, tailwind-merge ^2.6.0, dan zod ^3.24.1 (package.json:20-2915).
⚠️ Nilai selain
"true"atau"false", misalnya"1", membuatenvVariables.parse(process.env)melemparZodErrorsaat modul dimuat. KarenaNEXT_PUBLIC_di-inline ke bundle klien, nilai yang salah juga merusak halaman, bukan hanya server.
Helper storage dan openGraph
src/lib/helper.ts menyediakan dua pembaca storage. getFromLocalStorage memeriksa typeof window !== 'undefined' lebih dahulu, dan getFromSessionStorage memeriksa typeof sessionStorage !== 'undefined'; keduanya mengembalikan null ketika objek itu tidak tersedia (src/lib/helper.ts:1-1316).
openGraph menyusun URL gambar dari siteName, description, logo, dan templateTitle opsional. Setiap bagian di-encodeURIComponent setelah di-trim, dan parameter templateTitle hanya ditempel bila dioper (src/lib/og.ts:10-2717). Perilaku ini dikunci oleh test di src/lib/__tests__/og.test.ts:3-1918, yang membahas penyertaan parameter tersebut; selengkapnya di Pengujian dengan Jest.
⚠️ Nilai bawaan
logomasih placeholderhttps://og.<your-domain>/images/logo.jpgdan host gambar memakaiog.<your-domain>. Komentar di berkas itu meminta domain dan logo diganti sebelum dipakai (src/lib/og.ts:10-2717). Pemakaian metadata Open Graph di layout dibahas di SEO, Sitemap, dan Deploy.