D
P
0

CSS & Tailwind

Tailwind v4 Men-Tree-Shake CSS Variable Saya → Teks Terkirim Putih Tak Terlihat di Produksi

7 Juni 2026·4 menit baca
Tailwind v4 Men-Tree-Shake CSS Variable Saya → Teks Terkirim Putih Tak Terlihat di Produksi

Bug ini istimewa karena tidak pernah muncul di lokal — hanya di produksi. Di sebuah situs yang saya bangun, eyebrow text kecil di atas judul hero seharusnya berwarna emas. Di mesin dev saya warnanya emas, sempurna. Begitu di-build dan di-deploy, teks itu terkirim putih — praktis tak terlihat di atas latar terang. Tidak ada error, tidak ada warning build, tidak ada yang gagal. Teksnya cuma… hilang secara visual.

Setelah menelusuri, penyebabnya: Tailwind v4 men-tree-shake CSS variable saya keluar dari CSS yang dikompilasi. Variable-nya resolve ke kosong, dan color jatuh mewarisi #fff dari parent.

Kenapa variable-nya hilang

Di Tailwind v4, token yang Anda definisikan di @theme tidak otomatis ikut ke CSS final. Tailwind hanya meng-emit @theme variable ke CSS terkompilasi kalau ada Tailwind utility yang benar-benar memakainya. Kalau tidak ada utility yang mengonsumsi token itu, ia di-tree-shake — dianggap kode mati.

Setup saya kira-kira begini:

@theme {
  --color-gold: oklch(0.78 0.09 85);
  --color-gold-light: oklch(0.86 0.06 85); /* varian -light */
}

Lalu eyebrow text-nya saya warnai dengan merujuk variable itu langsung:

.hero-eyebrow {
  color: var(--color-gold-light);
}

Masalahnya: tidak pernah ada utility seperti text-gold-light yang dipakai di markup mana pun. Saya cuma memakai variable-nya di CSS tulisan tangan. Dari sudut pandang Tailwind, --color-gold-light tidak pernah dikonsumsi utility apa pun, jadi ia tidak dimasukkan ke output produksi.

Di lokal sering tidak ketahuan karena dev server kadang menyertakan lebih banyak token, atau urutan rebuild-nya berbeda. Di build produksi, tree-shaking-nya agresif: --color-gold-light lenyap dari CSS. Maka var(--color-gold-light) resolve ke nilai kosong, color jadi invalid, dan elemen mewarisi color: #fff dari kontainer hero di atasnya. Emas → putih.

Diagnostik yang langsung membuktikannya: grep CSS hasil kompilasi untuk melihat token --color-* mana yang benar-benar ikut.

# Lihat custom property mana yang benar-benar masuk ke output produksi
grep -o '\-\-color-[a-z-]*' dist/assets/*.css | sort -u
# --color-gold  ada
# --color-gold-light  TIDAK ADA  → di-tree-shake keluar

Begitu --color-gold-light tidak muncul di hasil grep padahal ada di sumber, jelas: Tailwind sudah membuangnya saat build.

Varian yang sama: arbitrary value yang tak pernah ter-compile

Saya juga kena versi lain dari bug yang sama dengan arbitrary class. Saya tulis sesuatu seperti text-[oklch(0.96_0.02_85/0.80)], dan ekspektasinya Tailwind menghasilkan selektor untuk warna itu. Yang terjadi: class itu tidak pernah ter-compile, dan teksnya tetap tak terlihat.

Penyebabnya, arbitrary class hanya menghasilkan selektor string-eksak kalau string persis itu ter-scan saat build. Tailwind juga mengkanonikalisasi nilai (misalnya /0.80 jadi /0.8), jadi selektor yang dihasilkan dan class yang ada di HTML bisa tidak cocok — alpha /0.80 versus /0.8 saja sudah cukup membuatnya meleset, dan aturannya tidak pernah match.

Solusi: pakai token yang stabil, atau beri fallback

Ada tiga cara memperbaikinya, dan saya pakai yang paling sesuai konteks:

1. Pakai utility token, bukan variable mentah. Kalau Anda memakai text-gold-light di markup, Tailwind menjamin token-nya ikut ter-emit:

<p class="hero-eyebrow text-gold-light">In conversation</p>

Karena utility-nya benar-benar dipakai, --color-gold-light tidak akan pernah di-tree-shake.

2. Beri var() sebuah fallback. Kalaupun variable-nya dibuang, fallback menjaga warna tetap muncul:

.hero-eyebrow {
  color: var(--color-gold-light, #d4c49b);
}

3. Hardcode hex-nya untuk nilai sekali pakai yang tidak butuh ikut sistem token:

.hero-eyebrow {
  color: #d4c49b;
}

Saya cenderung memilih opsi 1 untuk warna yang bagian dari design system, dan opsi 2 sebagai jaring pengaman murah di mana pun saya merujuk theme var di CSS tulisan tangan.

Catatan tambahan

  • Mental model untuk Tailwind v4: @theme mendefinisikan token, tapi token hanya sampai ke produksi kalau dikonsumsi sebuah utility. Merujuk var(--color-x) di CSS tulisan tangan tidak dihitung sebagai konsumsi.
  • Jadikan langkah grep tadi bagian dari verifikasi build: cek dengan cepat --color-* mana yang benar-benar ada di CSS terkompilasi. Lima detik ngecek lebih murah daripada satu jam menerka.
  • Hati-hati dengan arbitrary class untuk warna brand. Kanonikalisasi nilai (/0.80/0.8, normalisasi spasi) membuatnya rapuh. Token bernama jauh lebih bisa diprediksi.
  • "Putih di produksi, benar di lokal" hampir selalu berarti sebuah custom property resolve ke kosong lalu mewarisi warna teks default. Ikuti rantai inherit-nya sampai ketemu var yang hilang.

Intinya: di Tailwind v4, sebuah CSS variable bukan lagi sesuatu yang otomatis ada — keberadaannya bergantung pada apakah build percaya variable itu terpakai. Begitu Anda memperlakukan token sebagai sesuatu yang harus "diperoleh keberadaannya" lewat utility atau dilindungi fallback, kelas bug "teks tak terlihat di produksi" ini pun lenyap.