Penyelarasan resource dalam framework JavaScript

Meningkatkan Largest Contentful Paint di seluruh ekosistem JavaScript.

Sebagai bagian dari project Aurora, Google telah bekerja sama dengan framework web populer untuk memastikan performanya baik sesuai dengan Data Web Inti. Angular dan Next.js telah menempatkan font menjadi inline, yang dijelaskan di bagian pertama artikel ini. Pengoptimalan kedua yang akan kita bahas adalah CSS penting inline yang sekarang diaktifkan secara default di Angular CLI dan memiliki implementasi yang sedang berlangsung di Nuxt.js.

Inline font

Setelah menganalisis ratusan aplikasi, tim Aurora menemukan bahwa developer sering menyertakan font dalam aplikasinya dengan mereferensikannya dalam elemen <head> dari index.html. Berikut adalah contoh tampilannya saat menyertakan Ikon Material:

<!doctype html>
<html lang="en">
<head>
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
  ...
</html>

Meskipun sepenuhnya valid dan berfungsi, pola ini memblokir rendering aplikasi dan memasukkan permintaan tambahan. Untuk lebih memahami apa yang terjadi, lihat kode sumber stylesheet yang dirujuk dalam HTML di atas:

/* fallback */
@font-face {
  font-family: 'Material Icons';
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.gstatic.com/font.woff2) format('woff2');
}

.material-icons {
  /*...*/
}

Perhatikan cara definisi font-face merujuk ke file eksternal yang dihosting di fonts.gstatic.com. Saat memuat aplikasi, browser harus terlebih dahulu mendownload stylesheet asli yang dirujuk di head.

Gambar yang menunjukkan cara situs membuat permintaan ke server dan mendownload stylesheet eksternal
Pertama, situs akan memuat stylesheet font.

Selanjutnya, browser mendownload file woff2, lalu akhirnya dapat melanjutkan rendering aplikasi.

Gambar yang menampilkan dua permintaan yang dibuat, satu untuk stylesheet font, yang kedua untuk file font.
Selanjutnya, permintaan dibuat untuk memuat font.

Peluang untuk pengoptimalan adalah mendownload stylesheet awal pada waktu build dan menyisipkannya di index.html. Tindakan ini akan melewati seluruh perjalanan bolak-balik ke CDN saat runtime, sehingga mengurangi waktu pemblokiran.

Saat mem-build aplikasi, permintaan dikirim ke CDN, tindakan ini akan mengambil stylesheet dan menyisipkannya ke dalam file HTML, sehingga menambahkan <link rel=preconnect> ke domain. Dengan menerapkan teknik ini, kita akan mendapatkan hasil berikut:

<!doctype html>
<html lang="en">
<head>
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin >
  <style type="text/css">
  @font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/font.woff2) format('woff2');}.material-icons{/*...*/}</style>
  ...
</html>

Penyisipan font kini tersedia di Next.js dan Angular

Saat developer framework menerapkan pengoptimalan di alat dasar, mereka mempermudah aplikasi yang sudah ada dan yang baru untuk mengaktifkannya, sehingga menghadirkan peningkatan ke seluruh ekosistem.

Peningkatan ini diaktifkan secara default dari Next.js v10.2 dan Angular v11. Keduanya memiliki dukungan untuk menyejajarkan font Google dan Adobe. Angular mengharapkan untuk memperkenalkan yang terakhir di v12.2.

Anda dapat menemukan implementasi inline font di Next.js di GitHub, dan lihat video yang menjelaskan pengoptimalan ini dalam konteks Angular.

Membuat CSS penting menjadi inline

Peningkatan lainnya melibatkan peningkatan metrik First Contentful Paint (FCP) dan Largest Contentful Paint (LCP) dengan membuat CSS penting menjadi inline. CSS penting halaman mencakup semua gaya yang digunakan pada rendering awalnya. Untuk mempelajari topik ini lebih lanjut, lihat Menunda CSS yang tidak penting.

Kami mengamati bahwa banyak aplikasi memuat gaya secara sinkron, yang memblokir rendering aplikasi. Perbaikan cepat adalah memuat gaya secara asinkron. Daripada memuat skrip dengan media="all", setel nilai atribut media ke print, dan setelah pemuatan selesai, ganti nilai atribut ke all:

<link rel="stylesheet" href="..." media="print" onload="this.media='all'">

Namun, praktik ini dapat menyebabkan konten yang tidak bergaya berkedip.

Halaman tampak berkedip saat gaya dimuat.

Video di atas menunjukkan rendering halaman, yang memuat gayanya secara asinkron. Kedipan terjadi karena browser mulai mendownload gaya terlebih dahulu, lalu merender HTML yang mengikutinya. Setelah browser mendownload gaya, browser memicu peristiwa onload dari elemen link, yang mengupdate atribut media ke all, dan menerapkan gaya ke DOM.

Selama waktu antara rendering HTML dan menerapkan gaya, halaman akan sebagian ditata gayanya. Saat browser menggunakan gaya tersebut, kita akan melihat kedipan, yang merupakan pengalaman pengguna yang buruk dan menyebabkan regresi di Pergeseran Tata Letak Kumulatif (CLS).

Penyisipan CSS penting, beserta pemuatan gaya asinkron, dapat meningkatkan perilaku pemuatan. Alat ternak menemukan gaya mana yang digunakan di halaman, dengan melihat pemilih dalam stylesheet dan mencocokkannya dengan HTML. Jika menemukan kecocokan, sistem akan mempertimbangkan gaya yang sesuai sebagai bagian dari CSS penting, dan membuatnya inline.

Perhatikan contohnya:

Larangan
<head>
   <link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'">
</head>
<body>
  <section>
    <button class="primary"></button>
  </section>
</body>
/* styles.css */
section button.primary {
  /* ... */
}
.list {
  /* ... */
}

Contoh sebelum inline.

Pada contoh di atas, ternak akan membaca dan mengurai konten styles.css, setelah itu cocok dengan dua pemilih dengan HTML dan menemukan bahwa kita menggunakan section button.primary. Terakhir, karakter akan menyisipkan gaya yang sesuai di <head> halaman sehingga menghasilkan:

Anjuran
<head>
  <link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'">
  <style>
  section button.primary {
    /* ... */
  }
  </style>
</head>
<body>
  <section>
    <button class="primary"></button>
  </section>
</body>

Contoh setelah inline.

Setelah menyisipkan CSS penting dalam HTML, Anda akan mendapati bahwa kedipan halaman akan hilang:

Halaman dimuat setelah CSS dibuat inline.

Penyisipan CSS penting kini tersedia di Angular dan diaktifkan secara default di v12. Jika Anda menggunakan v11, aktifkan dengan menetapkan properti inlineCritical ke true di angular.json. Untuk menggunakan fitur ini di Next.js, tambahkan experimental: { optimizeCss: true } ke next.config.js Anda.

Kesimpulan

Dalam postingan ini, kami menyinggung beberapa kolaborasi antara Chrome dan framework web. Jika Anda adalah penulis framework dan mengenali beberapa masalah yang kami tangani dalam teknologi Anda, semoga temuan kami dapat menginspirasi Anda untuk menerapkan pengoptimalan performa serupa.

Cari tahu peningkatannya lebih lanjut. Anda dapat menemukan daftar lengkap upaya pengoptimalan yang telah kami lakukan untuk Data Web Inti dalam postingan Memperkenalkan Aurora.