การใส่ทรัพยากรในเฟรมเวิร์ก JavaScript

การปรับปรุง Largest Contentful Paint ในระบบนิเวศของ JavaScript

Google ได้ร่วมมือกับเฟรมเวิร์กเว็บยอดนิยมเพื่อให้มั่นใจว่าทํางานได้ดีตาม Core Web Vitals ซึ่งเป็นส่วนหนึ่งของโปรเจ็กต์ Aurora Angular และ Next.js มีแบบอักษรอยู่ในบรรทัดแล้ว ซึ่งมีอธิบายไว้ในส่วนแรกของบทความนี้ การเพิ่มประสิทธิภาพอย่างที่ 2 ที่เราจะพูดถึงคือ CSS In-line ที่สำคัญซึ่งตอนนี้มีการเปิดใช้โดยค่าเริ่มต้นใน Angular CLI และอยู่ระหว่างการติดตั้งใช้งานใน Nuxt.js

การใส่ตัวอักษร

หลังจากวิเคราะห์แอปพลิเคชันหลายร้อยรายการ ทีม Aurora พบว่านักพัฒนาซอฟต์แวร์มักจะใส่แบบอักษรไว้ในแอปพลิเคชันโดยอ้างอิงแบบอักษรเหล่านั้นในองค์ประกอบ <head> ของ index.html ต่อไปนี้เป็นตัวอย่างลักษณะที่ปรากฏเมื่อใส่ไอคอน Material

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

แม้ว่ารูปแบบนี้ถูกต้องและใช้งานได้โดยสมบูรณ์ แต่จะบล็อกการแสดงผลของแอปพลิเคชันและทำให้เกิดคำขอเพิ่มเติม เพื่อให้เข้าใจสิ่งที่เกิดขึ้น ให้ดูซอร์สโค้ดของสไตล์ชีตที่อ้างอิงใน HTML ด้านบน

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

สังเกตว่าคำจำกัดความ font-face อ้างอิงถึงไฟล์ภายนอกที่โฮสต์ใน fonts.gstatic.com อย่างไร ในการโหลดแอปพลิเคชัน เบราว์เซอร์จะต้องดาวน์โหลดสไตล์ชีตต้นฉบับที่อ้างอิงในส่วนหัวก่อน

รูปภาพแสดงวิธีที่เว็บไซต์ส่งคำขอไปยังเซิร์ฟเวอร์และดาวน์โหลดสไตล์ชีตภายนอก
ขั้นแรก เว็บไซต์จะโหลดสไตล์ชีตของแบบอักษร

ถัดไป เบราว์เซอร์จะดาวน์โหลดไฟล์ woff2 และในที่สุดก็จะแสดงผลแอปพลิเคชันต่อไปได้

รูปภาพแสดงคำขอที่สร้างขึ้น 2 รายการ รายการแรกสำหรับสไตล์ชีตแบบอักษร คำขอที่สองสำหรับไฟล์แบบอักษร
ต่อไปจะมีคำขอให้โหลดแบบอักษร

โอกาสในการเพิ่มประสิทธิภาพคือการดาวน์โหลดสไตล์ชีตเริ่มต้น ณ เวลาบิลด์และแทรกในบรรทัดใน index.html ซึ่งจะข้ามการเดินทางไปยัง CDN ตลอดเส้นทางขณะรันไทม์ จึงช่วยลดเวลาในการบล็อก

เมื่อสร้างแอปพลิเคชัน จะมีการส่งคำขอไปยัง CDN ซึ่งจะดึงสไตล์ชีตและในบรรทัดภายในไฟล์ HTML และเพิ่ม <link rel=preconnect> ไปยังโดเมน เมื่อนำเทคนิคนี้ไปใช้ เราจะได้ผลลัพธ์ดังต่อไปนี้

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

การแทรกแบบอักษรพร้อมใช้งานใน Next.js และ Angular แล้ว

เมื่อนักพัฒนาเฟรมเวิร์กนำการเพิ่มประสิทธิภาพไปใช้ในเครื่องมือที่สำคัญ นักพัฒนาเฟรมเวิร์กทั้งเก่าและใหม่สามารถเปิดใช้ได้ง่ายขึ้น ซึ่งจะนำการปรับปรุงไปสู่ทั้งระบบนิเวศ

การปรับปรุงนี้เปิดใช้โดยค่าเริ่มต้นจาก Next.js v10.2 และ Angular v11 ทั้ง 2 แบบรองรับการใส่แบบอักษร Google และ Adobe Angular คาดว่าจะเปิดตัวรุ่นหลังใน v12.2

คุณสามารถค้นหาการใช้งานการใส่แบบอักษรใน Next.js ใน GitHub และดูวิดีโออธิบายการเพิ่มประสิทธิภาพนี้ในบริบทของ Angular

การใส่ CSS ที่สำคัญ

การเพิ่มประสิทธิภาพอีกอย่างคือการปรับปรุงเมตริก First Contentful Paint (FCP) และ Largest Contentful Paint (LCP) โดยการใส่ CSS ที่สำคัญ CSS ที่สำคัญของหน้าเว็บประกอบด้วยสไตล์ทั้งหมดที่ใช้ในการแสดงผลครั้งแรก ดูข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อนี้ได้ที่เลื่อน CSS ที่ไม่สำคัญ

เราสังเกตเห็นว่าแอปพลิเคชันจำนวนมากโหลดสไตล์แบบพร้อมกันซึ่งบล็อกการแสดงผลของแอปพลิเคชัน วิธีแก้ไขด่วนคือการโหลดรูปแบบไม่พร้อมกัน แทนการโหลดสคริปต์ด้วย media="all" ให้ตั้งค่าของแอตทริบิวต์ media เป็น print และเมื่อการโหลดเสร็จสมบูรณ์แล้ว ให้เปลี่ยนค่าแอตทริบิวต์เป็น all ดังนี้

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

อย่างไรก็ตาม วิธีนี้อาจทำให้เนื้อหาที่ไม่มีสไตล์กะพริบ

หน้าเว็บกะพริบเมื่อรูปแบบโหลดขึ้น

วิดีโอด้านบนแสดงการแสดงผลหน้าเว็บซึ่งโหลดรูปแบบไม่พร้อมกัน ปัญหาหน้าเว็บสั่นเกิดขึ้นเนื่องจากเบราว์เซอร์เริ่มดาวน์โหลดสไตล์ก่อน จากนั้นจึงแสดงผล HTML ที่ตามมา เมื่อดาวน์โหลดรูปแบบแล้ว เบราว์เซอร์จะทริกเกอร์เหตุการณ์ onload ขององค์ประกอบลิงก์ อัปเดตแอตทริบิวต์ media เป็น all และใช้รูปแบบกับ DOM

ในช่วงเวลาระหว่างการแสดงผล HTML และนำสไตล์ไปใช้ จะไม่มีการจัดรูปแบบของหน้าเว็บบางส่วน เมื่อเบราว์เซอร์ใช้สไตล์ต่างๆ เราจะเห็นหน้าเว็บกะพริบ ซึ่งเป็นประสบการณ์ของผู้ใช้ที่ไม่ดีและส่งผลให้เกิดการถดถอยใน Cumulative Layout Shift (CLS)

การใส่ข้อมูลลงใน CSS ที่สำคัญ รวมถึงการโหลดสไตล์แบบอะซิงโครนัสจะช่วยปรับปรุงลักษณะการโหลดได้ เครื่องมือ critter จะค้นหาสไตล์ที่ใช้ในหน้าเว็บ โดยดูที่ตัวเลือกในสไตล์ชีตและจับคู่รูปแบบกับ HTML เมื่อพบรูปแบบที่ตรงกัน ระบบจะพิจารณาสไตล์ที่สอดคล้องกันเป็นส่วนหนึ่งของ CSS ที่สำคัญ และแทรกในบรรทัด

ยกตัวอย่างเช่น:

ไม่ควรทำ
<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 {
  /* ... */
}

ตัวอย่างก่อนแทรกในบรรทัด

ในตัวอย่างด้านบน สัตว์ประหลาดจะอ่านและแยกวิเคราะห์เนื้อหาของ styles.css จากนั้นจะจับคู่กับตัวเลือก 2 ตัวกับ HTML และพบว่าเราใช้ section button.primary สุดท้าย คริตเตอร์จะแทรกในบรรทัดของรูปแบบที่สอดคล้องกันใน <head> ของหน้าเว็บ ซึ่งส่งผลให้:

ควรทำ
<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>

ตัวอย่างหลังจากแทรกในบรรทัด

หลังจากแทรก CSS ที่สำคัญใน HTML คุณจะพบว่าหน้าเว็บกะพริบหายไปแล้ว:

การโหลดหน้าเว็บหลังจากการแทรก CSS

ขณะนี้การแทรกในบรรทัดของ CSS ที่สำคัญพร้อมใช้งานใน Angular และเปิดใช้งานโดยค่าเริ่มต้นใน v12 แล้ว หากใช้ v11 อยู่ ให้เปิดใช้โดยการตั้งค่าพร็อพเพอร์ตี้ inlineCritical เป็น true ใน angular.json หากต้องการเลือกใช้ฟีเจอร์นี้ใน Next.js ให้เพิ่ม experimental: { optimizeCss: true } ลงใน next.config.js

บทสรุป

ในโพสต์นี้ เราได้พูดถึงการทำงานร่วมกันบางส่วนระหว่าง Chrome และเว็บเฟรมเวิร์ก หากคุณเป็นผู้สร้างเฟรมเวิร์กและทราบถึงปัญหาบางอย่างที่เราจัดการในเทคโนโลยีของคุณ เราหวังว่าข้อมูลของเราจะเป็นแรงบันดาลใจให้คุณนำการเพิ่มประสิทธิภาพการทำงานลักษณะนี้ไปใช้

ดูข้อมูลเพิ่มเติมเกี่ยวกับการปรับปรุง คุณดูรายการงานเพิ่มประสิทธิภาพทั้งหมดที่เราทำสำหรับ Core Web Vitals ได้ในโพสต์ขอแนะนำ Aurora