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

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

ฮูเซน จอร์เดห์
ฮูสเซน จอร์เดห์

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

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

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

มีประโยชน์อย่างไร

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

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

การแสดงผลล่วงหน้าเป็นเทคนิคแยกต่างหากที่มีความซับซ้อนน้อยกว่าการแสดงผลจากเซิร์ฟเวอร์ แต่ก็มีวิธีในการปรับปรุงเวลาของ 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 แบบคงที่เป็นเพย์โหลดสำหรับแต่ละเส้นทางที่ทำการ Crawl คุณสามารถดูลักษณะของเพย์โหลด HTML ได้โดยคลิก URL ของคำขอ HTML แล้วคลิกแท็บตัวอย่างในเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome

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

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

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

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

"reactSnap": {
  "inlineCss": true
}

การดูตัวอย่างการตอบกลับในเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome จะแสดงหน้าที่จัดรูปแบบโดยมี CSS ที่สำคัญในบรรทัด

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

บทสรุป

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

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