เส้นทางที่แสดงผลล่วงหน้าด้วยฟีเจอร์ Snap-Snap

หากไม่มีการแสดงผลฝั่งเซิร์ฟเวอร์ แต่ยังต้องการเพิ่มประสิทธิภาพของเว็บไซต์ React อยู่ ลองแสดงผลล่วงหน้า

react-snap เป็นไลบรารีของบุคคลที่สามที่แสดงผลหน้าในเว็บไซต์ของคุณล่วงหน้าเป็นไฟล์ HTML แบบคงที่ ซึ่งอาจช่วยปรับปรุงเวลาของ First Paint ในแอปพลิเคชัน

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

การเปรียบเทียบการโหลดแบบแสดงข้างกัน เวอร์ชันที่ใช้การแสดงผลล่วงหน้าจะโหลดได้เร็วขึ้น 4.2 วินาที

เหตุใดจึงมีประโยชน์

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

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

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

รีแอ็ก-สแนป

react-snap ใช้ Puppeteer เพื่อสร้างไฟล์ HTML ที่แสดงผลล่วงหน้าของเส้นทางต่างๆ ในแอปพลิเคชัน หากต้องการเริ่มต้น ให้ติดตั้งเป็นทรัพยากร Dependency ของการพัฒนา ดังนี้

npm install --save-dev react-snap

จากนั้นเพิ่มสคริปต์ postbuild ใน package.json ดังนี้

"scripts": {
  //...
  "postbuild": "react-snap"
}

การดำเนินการนี้จะเรียกใช้คำสั่ง react-snap โดยอัตโนมัติทุกครั้งที่มีการสร้างบิลด์ใหม่ของแอปพลิเคชัน (npm build)

สิ่งสุดท้ายที่คุณต้องทำก็คือเปลี่ยนวิธีเปิดเครื่องของแอปพลิเคชัน เปลี่ยนไฟล์ src/index.js เป็นดังนี้

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));
const rootElement = document.getElementById("root");

if (rootElement.hasChildNodes()) {
  ReactDOM.hydrate(<App />, rootElement);
} else {
  ReactDOM.render(<App />, rootElement);
}

แทนที่จะใช้เพียง ReactDOM.render เพื่อแสดงผลเอลิเมนต์ React รูทใน DOM โดยตรง การดำเนินการนี้จะตรวจสอบเพื่อดูว่ามีโหนดย่อยอยู่ไหม เพื่อระบุว่าเนื้อหา HTML มีการแสดงผลล่วงหน้า (หรือแสดงผลบนเซิร์ฟเวอร์) หรือไม่ หากเป็นเช่นนั้น ระบบจะใช้ ReactDOM.hydrate เพื่อแนบ Listener เหตุการณ์กับ HTML ที่สร้างขึ้นใหม่แทนการแนบรายการใหม่

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

การเปรียบเทียบก่อนและหลัง ภาพหลังการถ่ายทำแสดงว่าเนื้อหาแสดงผลแล้ว

Flash ของเนื้อหาที่ไม่ได้จัดรูปแบบ

แม้ว่าขณะนี้ HTML แบบคงที่จะแสดงผลแทบจะในทันที แต่ HTML จะยังคงไม่มีการจัดรูปแบบโดยค่าเริ่มต้น ซึ่งอาจทำให้เกิดปัญหาในการแสดง "รูปแบบแฟลชของเนื้อหาที่ไม่มีการจัดรูปแบบ" (FOUC) กรณีนี้จะสังเกตเห็นได้ชัดเจนเป็นพิเศษหากคุณใช้ไลบรารี CSS-in-JS เพื่อสร้างตัวเลือก เนื่องจากแพ็กเกจ JavaScript จะต้องดําเนินการให้เสร็จก่อนจึงจะนํารูปแบบใดๆ มาใช้ได้

คุณสามารถแทรก CSS ที่สำคัญ หรือจำนวน CSS ขั้นต่ำที่จำเป็นต้องใช้ในการแสดงผลหน้าแรกไว้ในบรรทัด <head> ของเอกสาร HTML โดยตรงเพื่อป้องกันปัญหานี้ react-snap ใช้ minimalcss ซึ่งเป็นไลบรารีของบุคคลที่สามอีกรายการเพื่อดึงข้อมูล CSS ที่สำคัญสำหรับเส้นทางต่างๆ คุณเปิดใช้ได้โดยระบุข้อมูลต่อไปนี้ในไฟล์ package.json

"reactSnap": {
  "inlineCss": true
}

การดูตัวอย่างการตอบกลับใน Chrome DevTools จะแสดงหน้าที่มีการจัดรูปแบบซึ่งมี CSS ที่สำคัญแทรกในบรรทัด

การเปรียบเทียบก่อนและหลัง ภาพ &quot;หลังการถ่ายทำ&quot; แสดงให้เห็นว่าเนื้อหาแสดงผลแล้วและมีการจัดรูปแบบเนื่องจาก CSS ที่สำคัญในบรรทัด

บทสรุป

หากคุณไม่ได้แสดงผลเส้นทางการแสดงผลฝั่งเซิร์ฟเวอร์ในแอปพลิเคชัน ให้ใช้ react-snap เพื่อแสดงผล HTML แบบคงที่ให้กับผู้ใช้

  1. ติดตั้งเป็นทรัพยากร Dependency ของการพัฒนาและเริ่มต้นด้วยการตั้งค่าเริ่มต้นเท่านั้น
  2. ใช้ตัวเลือก inlineCss แบบทดลองเพื่อแทรก CSS ที่สำคัญในหน้าหากใช้งานกับเว็บไซต์ของคุณได้
  3. หากคุณใช้การแยกโค้ดในระดับคอมโพเนนต์ภายในเส้นทางใดก็ตาม โปรดระมัดระวังอย่าแสดงผลสถานะการโหลดให้กับผู้ใช้ล่วงหน้า react-snap README จะอธิบายเกี่ยวกับเรื่องนี้โดยละเอียดยิ่งขึ้น