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

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

Google ทำงานร่วมกับเฟรมเวิร์กเว็บยอดนิยมเพื่อช่วยให้เฟรมเวิร์กเหล่านั้นทำงานได้ดีตาม Core Web Vitals ภายใต้โปรเจ็กต์ Aurora Angular และ Next.js ได้เข้าสู่แบบอักษรในบรรทัดแล้ว ซึ่งอธิบายไว้ในส่วนแรกของบทความนี้ การเพิ่มประสิทธิภาพที่ 2 ที่จะกล่าวถึงคือการฝัง CSS ที่สำคัญ ซึ่งตอนนี้เปิดใช้โดยค่าเริ่มต้นใน 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 รายการที่สร้างขึ้น รายการแรกสำหรับสไตล์ชีตแบบอักษร และรายการที่ 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 กับการใช้สไตล์ หน้าเว็บจะไม่มีสไตล์บางส่วน เมื่อเบราว์เซอร์ใช้สไตล์ดังกล่าว เราเห็นการกะพริบ ซึ่งทำให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่ไม่ดีและส่งผลให้การจัดวางแบบสะสมที่เปลี่ยนไป (CLS) ลดลง

การแทรก CSS ที่สําคัญในหน้าพร้อมกับการโหลดสไตล์แบบไม่พร้อมกันจะช่วยปรับปรุงลักษณะการโหลดได้ เครื่องมือ Critters จะค้นหาสไตล์ที่ใช้ในหน้าเว็บโดยดูที่ตัวเลือกในสไตล์ชีตและจับคู่กับ 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 {
  /* ... */
}

ตัวอย่างก่อนการฝัง

ในตัวอย่างข้างต้น Critters จะอ่านและแยกวิเคราะห์เนื้อหาของ styles.css จากนั้นจะจับคู่ตัวเลือก 2 รายการกับ HTML และพบว่าเราใช้ section button.primary สุดท้าย Critter จะแทรกสไตล์ที่เกี่ยวข้องใน <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