Optimasi Core Web Vitals di Astro: Meningkatkan LCP, CLS, dan INP untuk Skor PageSpeed

Lhuqita Fazry
Web Development Astro Core Web Vitals Performance Lighthouse
Optimasi Core Web Vitals di Astro: Meningkatkan LCP, CLS, dan INP untuk Skor PageSpeed

Tiga Metrik yang Menentukan Pengalaman Nyata Pengunjung

Core Web Vitals mengukur pengalaman pengunjung lewat tiga metrik yang saling melengkapi. LCP (Largest Contentful Paint) mencatat waktu sampai elemen terbesar di viewport selesai dirender. CLS (Cumulative Layout Shift) menghitung seberapa jauh layout bergeser tanpa diminta pengunjung. INP (Interaction to Next Paint) mengukur jeda antara interaksi pengguna dan respons visual berikutnya.

PageSpeed Insights memakai ambang batas yang cukup tegas untuk ketiga metrik tersebut. Nilai LCP di bawah 2,5 detik, CLS di bawah 0,1, dan INP di bawah 200 milidetik masuk kategori baik. Nilai di atas ambang itu ditandai sebagai perlu perbaikan, dan angka yang jauh di atasnya masuk kategori buruk.

Astro sudah memberi keunggulan awal pada dua dari tiga metrik. Halaman dikirim sebagai HTML statis, JavaScript hanya dimuat untuk komponen island yang benar-benar interaktif, dan tidak ada hydration runtime global. Dua keuntungan ini membuat LCP lebih cepat dirender dan INP lebih responsif dibanding aplikasi yang menghidrasi seluruh halaman.

Keunggulan bawaan tidak otomatis menghasilkan skor hijau. Hero image berukuran besar tanpa prioritas tetap memperlambat LCP. Komponen island yang menyisipkan konten setelah halaman tampil tetap menggeser layout. Handler interaksi yang berat tetap membuat INP melonjak. Fokus artikel ini adalah menemukan penyebab tersebut di kode proyek Astro, memperbaikinya dengan perubahan terukur, lalu memverifikasi hasilnya lewat Lighthouse.

Membaca Hasil Lighthouse dan Menghubungkannya ke Kode

Laporan PageSpeed Insights memuat dua jenis data yang perlu dibedakan. Field data berasal dari CrUX dan merangkum pengalaman pengunjung nyata selama 28 hari terakhir. Lab data berasal dari satu kali audit Lighthouse dengan perangkat dan jaringan yang disimulasikan. Field data cocok untuk menilai kondisi produksi, sedangkan lab data cocok untuk mereproduksi masalah secara lokal.

Bagian yang paling berguna untuk debugging ada di daftar peluang perbaikan dan diagnostik. Untuk LCP, laporan menunjuk elemen konkret yang menjadi kandidat terbesar, misalnya gambar hero atau heading utama. Untuk CLS, laporan mendaftar elemen dengan kontribusi pergeseran terbesar beserta penyebabnya. Untuk INP, kita perlu membuka panel Performance dan merekam interaksi yang lambat, karena Lighthouse tidak selalu menangkap interaksi nyata pengunjung.

Workflow audit yang konsisten membuat perbaikan bisa dibandingkan. Kita build proyek dalam mode produksi, jalankan preview, lalu audit halaman yang sama dengan kondisi throttling yang sama setiap kali.

bash
npm run build
npx astro preview --port 4321

npx lighthouse http://localhost:4321 \
  --only-categories=performance \
  --preset=desktop \
  --output=json \
  --output-path=./reports/baseline.json

Perintah di atas menyimpan laporan baseline.json sebagai pembanding. Setelah satu perubahan diterapkan, jalankan perintah yang sama dengan nama file berbeda, lalu bandingkan nilai LCP, CLS, dan INP antar laporan. Audit pada build produksi penting karena build development memuat modul tambahan yang tidak ada di produksi, sehingga angkanya menyesatkan.

Mempercepat LCP dengan Prioritas Aset yang Benar

Penyebab LCP lambat di proyek Astro biasanya berulang. Gambar hero dikirim dalam resolusi penuh tanpa format modern. Font eksternal memblokir render teks. CSS kritis dimuat setelah JavaScript lain selesai. Selain itu, komponen island yang terlalu tinggi di halaman menunda elemen utama muncul.

Komponen Image dari astro:assets menangani tiga hal sekaligus: konversi format ke webp atau avif, pembuatan beberapa ukuran responsif, dan penambahan atribut dimensi. Atribut loading="eager" dan fetchpriority="high" hanya diberikan pada gambar yang berada di atas lipatan halaman. Gambar lain tetap loading="lazy" agar bandwidth tidak dipakai untuk aset yang belum terlihat.

astro
---
import { Image } from 'astro:assets';
import heroPerf from '../assets/hero-performance.jpg';
---

<section class="hero">
  <Image
    src={heroPerf}
    alt="Dashboard performa website dengan grafik Core Web Vitals"
    widths={[640, 960, 1280]}
    sizes="(max-width: 768px) 100vw, 60vw"
    loading="eager"
    fetchpriority="high"
    format="webp"
  />
  <h1>Optimasi Core Web Vitals di Astro</h1>
</section>

Susunan ini membuat browser memilih ukuran gambar sesuai lebar viewport, bukan mengunduh satu file besar untuk semua perangkat. Prioritas tinggi memastikan permintaan gambar dikirim sebelum aset sekunder, sehingga elemen terbesar muncul lebih cepat.

Langkah yang sama berlaku untuk font. Cukup satu file font utama yang di-preload, dan deklarasikan font-display: swap agar teks tetap tampil dengan font fallback selama file dimuat.

astro
<link
  rel="preload"
  href="/fonts/inter-latin.woff2"
  as="font"
  type="font/woff2"
  crossorigin
/>
Advanced Architecture with Laravel Containers & Queues
Web App • Intermediate

Advanced Architecture with Laravel Containers & Queues

A problem-driven, project-based course designed to elevate intermediate develope...

Register

Hasil yang diharapkan adalah penurunan LCP pada laporan berikutnya, biasanya dari kisaran tiga detik ke bawah 2,5 detik untuk halaman artikel. Bila angka belum turun, periksa kembali elemen LCP yang dilaporkan, karena kandidatnya bisa berpindah dari gambar ke heading setelah perbaikan pertama.

Perbandingan render halaman antara FCP dan LCP pada tampilan mobile

Gambar: Urutan render halaman dari FCP sampai elemen terbesar selesai dilukis sebagai LCP — Sumber: web.dev

Menghilangkan CLS dari Gambar, Font, dan Komponen Island

CLS muncul ketika browser harus mengubah posisi elemen yang sudah terlihat. Tiga sumber paling sering di proyek Astro adalah gambar tanpa rasio aspek, font swap yang mengubah tinggi baris, dan island yang menyisipkan konten setelah hydration selesai.

Skala ambang Cumulative Layout Shift dengan batas baik di bawah 0,1

Gambar: Ambang penilaian CLS, di mana nilai di bawah 0,1 masuk kategori baik dan di atas 0,25 masuk kategori buruk — Sumber: web.dev

Perbaikan untuk gambar cukup eksplisit: berikan width dan height atau wadah dengan aspect-ratio. Browser memakai informasi tersebut untuk menyiapkan ruang sebelum file gambar selesai diunduh. Untuk font, fallback dengan metrik mirip dan size-adjust mengurangi pergeseran teks saat font utama aktif.

Island memerlukan pendekatan berbeda. Directive client:visible menunda hydration sampai komponen masuk viewport, dan penundaan itu membuat komponen baru menggambar isinya ketika pengunjung sudah menggulir. Ruang tetap harus disiapkan sebelum hydration terjadi.

astro
---
import { Image } from 'astro:assets';
import PriceChart from '../components/PriceChart.tsx';
import cover from '../assets/cover-pricing.jpg';
---

<article class="card">
  <div class="card__media">
    <Image src={cover} alt="Ilustrasi paket harga" width={480} height={270} loading="lazy" />
  </div>
  <div class="card__island">
    <PriceChart client:visible />
  </div>
</article>

<style>
  .card__media {
    aspect-ratio: 16 / 9;
    overflow: hidden;
  }

  .card__media :global(img) {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .card__island {
    min-height: 220px;
  }
</style>

Kelas card__island menyediakan tinggi minimum yang sama dengan tinggi komponen setelah hydration. Ketika PriceChart selesai dimuat, ruangnya sudah ada, sehingga tidak ada pergeseran layout. Hasil yang diharapkan adalah CLS mendekati nol pada laporan Lighthouse, dan grafik Layout Shift di panel Performance tidak lagi menampilkan bar pergeseran besar.

Meningkatkan INP lewat Strategi Hydration dan JavaScript Minimal

INP mengukur jeda dari input pengguna sampai frame berikutnya tampil. Jeda ini membengkak ketika main thread sibuk, misalnya saat hydration berjalan, saat handler melakukan komputasi berat, atau saat banyak komponen dimuat sekaligus.

Skala ambang Interaction to Next Paint dengan kategori baik di bawah 200 milidetik

Gambar: Ambang penilaian INP, dengan batas 200 milidetik untuk kategori baik dan 500 milidetik untuk kategori buruk — Sumber: web.dev

Pemilihan directive hydration adalah keputusan paling berpengaruh. client:load hanya untuk kontrol yang harus siap sejak halaman tampil, seperti tombol navigasi utama. client:idle cocok untuk widget yang boleh menunggu browser senggang, misalnya kotak pencarian atau toggle tema. client:only dipakai ketika komponen memang tidak bisa dirender di server.

Selain directive, pekerjaan di dalam handler perlu dipisahkan antara update mendesak dan update yang bisa ditunda. Pada framework reaktif, mekanisme transisi menandai update berat sebagai non-urgent sehingga input pengguna tetap dilukis lebih dulu.

tsx
import { useState } from 'preact/hooks';

export default function SearchBox() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState<string[]>([]);

  async function handleInput(event: Event) {
    const value = (event.target as HTMLInputElement).value;
    setQuery(value);

    const found = await filterCatalog(value);
    setResults(found);
  }

  return (
    <div class="search">
      <input value={query} onInput={handleInput} placeholder="Cari produk" />
      {results.length > 0 && <ul>{results.map((item) => <li>{item}</li>)}</ul>}
    </div>
  );
}

Komponen tersebut dipasang dengan client:idle di halaman Astro, sehingga hydration tidak berebut waktu dengan render awal. Fungsi filterCatalog sebaiknya melakukan pekerjaan berat di luar render, misalnya dengan requestIdleCallback atau pemrosesan indeks yang sudah disiapkan sebelumnya.

Untuk mengukur hasilnya, rekam interaksi di panel Performance lalu cari long task di atas 50 milidetik. Pindahkan pekerjaan dari event handler ke langkah terpisah, dan ulangi pengukuran sampai INP turun di bawah 200 milidetik. Pada banyak kasus, perubahan directive saja sudah memangkas jeda interaksi secara signifikan karena hydration tidak lagi menahan input pertama.

Menjaga Skor Stabil dengan Pengukuran Berkelanjutan

Skor yang sudah hijau akan turun kembali ketika artikel bertambah, dependensi diperbarui, atau komponen baru ditambahkan. Karena itu pengukuran perlu menjadi bagian dari pipeline, bukan aktivitas sekali jalan.

Lighthouse CI menjalankan audit pada setiap push dan menggagalkan build ketika metrik melewati anggaran yang ditetapkan. Konfigurasi lighthouserc.json menyimpan ambang batas untuk ketiga metrik utama.

json
{
  "ci": {
    "collect": { "staticDistDir": "./dist" },
    "assert": {
      "assertions": {
        "largest-contentful-paint": ["error", { "maxNumericValue": 2500 }],
        "cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }],
        "interaction-to-next-paint": ["error", { "maxNumericValue": 200 }]
      }
    }
  }
}

Workflow GitHub Actions cukup memanggil @lhci/cli autorun setelah proses build selesai. Bila salah satu ambang terlampaui, pipeline berhenti dengan status gagal dan laporan HTML bisa diunduh sebagai artefak untuk diperiksa.

yaml
name: performance-budget

on:
  push:
    branches: [main]

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: npm run build
      - run: npx @lhci/cli autorun

Selain lab data, kirim field data dari pengunjung nyata memakai library web-vitals. Data lapangan menunjukkan kondisi perangkat dan jaringan yang tidak bisa direplikasi Lighthouse, sehingga keputusan optimasi tetap berpijak pada pengalaman pengguna.

Urutan prioritas perbaikan yang praktis: selesaikan LCP lebih dulu karena berdampak langsung pada persepsi kecepatan, lanjutkan ke CLS agar halaman terasa stabil, lalu tutup dengan INP melalui penyederhanaan hydration. Daftar periksa akhirnya sederhana: gambar responsif dengan dimensi eksplisit, font terbatas dengan preload seperlunya, island sesedikit mungkin, dan tidak ada komponen dinamis yang menyisipkan konten tanpa ruang cadangan.

Ingin membangun website Astro yang cepat sejak awal dengan praktik performa yang terukur? Program Web Development di Rumah Coding membahas arsitektur Astro, Core Web Vitals, dan performance budget langsung melalui proyek nyata.

Course Terkait

Asynchronous Bulk E-Certificate & Notification Engine
Premium Course Web App

Advanced Architecture with Laravel Containers & Queues

A problem-driven, project-based course designed to elevate intermediate developers to a senior architectural mindset. Instead of just memorizing documentation, students will tackle real-world bottleneck issues by mastering the Inversion of Control (IoC) principle, Dependency Injection, and asynchronous background processing. Learn to decouple services and orchestrate robust queues to build scalable, high-performance applications that never freeze under heavy loads.

Capstone Project

Asynchronous Bulk E-Certificate & Notification Engine

  • Decoupled Service Architecture: PDF generation and Email delivery are built as independent, interface-driven services injected via the Service Container.
  • Job Chaining: Ensuring processes run in strict asynchronous order (Generate PDF ➔ Upload to Storage ➔ Send Email).
  • Job Batching & Real-Time Tracking: Grouping hundreds of jobs together and displaying a live progress bar (e.g., "65% Completed") on the admin dashboard.
7 Weeks Intermediate
View Course Details
EduTrack: Learning Management & Assessment API
Premium Course Web App

API Development with Golang

A hands-on, project-based course designed to teach beginners how to build robust, high-performance RESTful APIs using Golang. Starting from core Go syntax and concurrency, students will progress through routing, database integration, security, and finally containerize their application for production deployment.

Capstone Project

EduTrack: Learning Management & Assessment API

  • Role-Based Access Control (RBAC)
  • Course & Module Management
  • Enrollment & Progress Tracking
7 Weeks Beginner
View Course Details
Mini Academic Portal (Learning Management System)
Premium Course Web App

Building Modern Apps with Filament

Learn how to build modern, full-stack web applications rapidly using FilamentPHP and the TALL stack. This project-based course is designed for beginners, guiding you step-by-step to create a fully functional backend administration panel. By the end of the course, you will have mastered Filament's powerful Panel Builder, robust CRUD operations, complex database relationships, and interactive dashboards.

Capstone Project

Mini Academic Portal (Learning Management System)

  • Master Data Management: Comprehensive CRUD functionality to manage Instructors and Course catalogs.
  • Student Registry: A dedicated module to manage student profiles and personal information.
  • Dynamic Enrollment System: Handling Many-to-Many relationships to enroll students into specific courses using Filament's pivot features.
7 Weeks Intermediate
View Course Details

Related Articles