Nội tuyến tài nguyên trong khung JavaScript

Cải thiện Thời gian hiển thị nội dung lớn nhất trên hệ sinh thái JavaScript.

Trong dự án Aurora, Google đã và đang làm việc với các khung web phổ biến để đảm bảo các khung này hoạt động tốt theo Các chỉ số quan trọng về trang web. Angular và Next.js đã cập nhật phông chữ cùng dòng, điều này được giải thích trong phần đầu tiên của bài viết này. Tính năng tối ưu hoá thứ hai mà chúng tôi sẽ đề cập là CSS quan trọng cùng dòng, hiện được bật theo mặc định trong Angular CLI và đang được triển khai trong Nuxt.js.

Phông chữ cùng dòng

Sau khi phân tích hàng trăm ứng dụng, nhóm Aurora nhận thấy rằng các nhà phát triển thường đưa phông chữ vào ứng dụng của họ bằng cách tham chiếu các phông chữ đó trong phần tử <head> của index.html. Sau đây là một ví dụ về cách hiển thị tuỳ chọn này khi sử dụng các Biểu tượng Material:

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

Mặc dù mẫu này hoàn toàn hợp lệ và hoạt động, nhưng nó chặn quá trình hiển thị của ứng dụng và đưa ra thêm một yêu cầu. Để hiểu rõ hơn về những gì đang diễn ra, hãy xem mã nguồn của biểu định kiểu được tham chiếu trong HTML ở trên:

/* 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 {
  /*...*/
}

Hãy lưu ý cách định nghĩa font-face tham chiếu đến một tệp bên ngoài được lưu trữ trên fonts.gstatic.com. Khi tải ứng dụng, trước tiên, trình duyệt phải tải biểu định kiểu ban đầu được tham chiếu trong phần đầu.

Hình ảnh cho thấy cách trang web phải gửi yêu cầu tới máy chủ và tải biểu định kiểu bên ngoài xuống
Đầu tiên, trang web tải biểu định kiểu phông chữ.

Tiếp theo, trình duyệt tải tệp woff2 xuống, rồi cuối cùng có thể tiến hành kết xuất ứng dụng.

Hình ảnh cho thấy hai yêu cầu được đưa ra, một cho biểu định kiểu phông chữ, hình ảnh thứ hai cho tệp phông chữ.
Tiếp theo, hệ thống sẽ gửi yêu cầu tải phông chữ.

Cơ hội để tối ưu hoá là tải biểu định kiểu ban đầu xuống tại thời điểm xây dựng và cùng dòng trong index.html. Điều này bỏ qua toàn bộ vòng tròn đến CDN trong thời gian chạy, giúp giảm thời gian chặn.

Khi tạo ứng dụng, một yêu cầu sẽ được gửi đến CDN. Thao tác này sẽ tìm nạp biểu định kiểu và đưa biểu định kiểu vào cùng dòng trong tệp HTML, thêm <link rel=preconnect> vào miền. Áp dụng kỹ thuật này, chúng ta sẽ có được kết quả sau:

<!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>

Tính năng nội tuyến phông chữ hiện có trong Next.js và Angular

Khi nhà phát triển khung triển khai tính năng tối ưu hoá trong công cụ cơ bản, họ sẽ giúp các ứng dụng hiện có và ứng dụng mới dễ dàng kích hoạt tính năng này hơn, mang lại sự cải thiện cho toàn bộ hệ sinh thái.

Cải tiến này được bật theo mặc định từ Next.js v10.2 và Angular v11. Cả hai đều hỗ trợ chèn cùng dòng phông chữ Google và Adobe. Angular dự kiến sẽ giới thiệu phần sau trong v12.2.

Bạn có thể tìm thấy cách triển khai nội dung phông chữ trong dòng trong Next.js trên GitHub, cũng như xem video giải thích về cách tối ưu hoá này trong bối cảnh của Angular.

Cùng dòng CSS quan trọng

Một tính năng nâng cao khác bao gồm việc cải thiện các chỉ số Thời gian hiển thị nội dung đầu tiên (FCP)Thời gian hiển thị nội dung lớn nhất (LCP) bằng cách chèn CSS quan trọng cùng dòng. CSS quan trọng của một trang bao gồm tất cả các kiểu được dùng trong lần hiển thị ban đầu. Để tìm hiểu thêm về chủ đề này, hãy xem phần Trì hoãn CSS không quan trọng.

Chúng tôi quan sát thấy nhiều ứng dụng đang tải các kiểu một cách đồng bộ, khiến ứng dụng bị chặn. Cách khắc phục nhanh là tải kiểu không đồng bộ. Thay vì tải tập lệnh bằng media="all", hãy đặt giá trị của thuộc tính media thành print và sau khi tải xong, hãy thay thế giá trị thuộc tính thành all:

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

Tuy nhiên, phương pháp này có thể gây ra hiện tượng nhấp nháy nội dung chưa định kiểu.

Trang có vẻ nhấp nháy khi tải kiểu.

Video ở trên cho thấy quá trình hiển thị một trang sẽ tải các kiểu của trang theo cách không đồng bộ. Tình trạng nhấp nháy này xảy ra vì trình duyệt bắt đầu tải các kiểu xuống trước rồi sau đó hiển thị HTML theo sau. Sau khi tải các kiểu xuống, trình duyệt sẽ kích hoạt sự kiện onload của phần tử liên kết, cập nhật thuộc tính media thành all và áp dụng các kiểu đó cho DOM.

Trong thời gian từ khi hiển thị HTML và áp dụng kiểu, trang chưa được tạo kiểu một phần. Khi trình duyệt sử dụng các kiểu, chúng ta sẽ thấy hiện tượng nhấp nháy. Đây là trải nghiệm không tốt cho người dùng và dẫn đến mức hồi quy trong Điểm số tổng hợp về mức thay đổi bố cục (CLS).

Nội dung CSS quan trọng cùng dòng, cùng với việc tải kiểu không đồng bộ, có thể cải thiện hành vi tải. Công cụ thực thể tìm thấy kiểu nào được sử dụng trên trang, bằng cách xem các bộ chọn trong biểu định kiểu và so khớp chúng với HTML. Khi tìm thấy một kết quả phù hợp, trình phân tích cú pháp sẽ xem các kiểu tương ứng là một phần của CSS quan trọng và đưa chúng vào nội tuyến.

Hãy xem ví dụ:

Không nên
<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 {
  /* ... */
}

Ví dụ trước khi cùng dòng.

Trong ví dụ trên, sinh vật sẽ đọc và phân tích cú pháp nội dung của styles.css, sau đó sinh vật khớp với hai bộ chọn với HTML và phát hiện ra rằng chúng ta sử dụng section button.primary. Cuối cùng, sinh vật sẽ cùng dòng các kiểu tương ứng trong <head> của trang, dẫn đến:

Nên
<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>

Ví dụ sau khi cùng dòng.

Sau khi nội tuyến CSS quan trọng trong HTML, bạn sẽ thấy trang nhấp nháy đã biến mất:

Trang tải sau khi CSS cùng dòng.

Các tính năng nội tuyến quan trọng của CSS hiện đã có trong Angular và được bật theo mặc định trong phiên bản 12. Nếu bạn đang dùng v11, hãy bật chế độ này bằng cách đặt thuộc tính inlineCritical thành true trong angular.json. Để chọn sử dụng tính năng này trong Next.js, hãy thêm experimental: { optimizeCss: true } vào next.config.js của bạn.

Kết luận

Trong bài đăng này, chúng ta đã đề cập đến một số hoạt động cộng tác giữa Chrome và các khung web. Nếu bạn là tác giả của chương trình khung này và nhận ra một số vấn đề mà chúng tôi đã giải quyết trong công nghệ của mình, thì chúng tôi hy vọng những phát hiện của mình sẽ thôi thúc bạn áp dụng các biện pháp tối ưu hoá hiệu suất tương tự.

Tìm hiểu thêm về những điểm cải tiến. Bạn có thể xem danh sách đầy đủ các công việc tối ưu hoá mà chúng tôi đã thực hiện cho Các chỉ số quan trọng về trang web trong bài đăng Giới thiệu Aurora.