หากไม่มีการแสดงผลฝั่งเซิร์ฟเวอร์ แต่ยังต้องการเพิ่มประสิทธิภาพของเว็บไซต์ React อยู่ ลองแสดงผลล่วงหน้า
react-snap
เป็นไลบรารีของบุคคลที่สามที่แสดงผลหน้าในเว็บไซต์ของคุณล่วงหน้าเป็นไฟล์ HTML แบบคงที่ ซึ่งอาจช่วยปรับปรุงเวลาของ First Paint ในแอปพลิเคชัน
ต่อไปนี้คือการเปรียบเทียบแอปพลิเคชันเดียวกันที่มีและไม่มีการแสดงผลล่วงหน้าที่โหลดขึ้นในการเชื่อมต่อ 3G และอุปกรณ์เคลื่อนที่ที่จำลองขึ้น
![การเปรียบเทียบการโหลดแบบแสดงข้างกัน เวอร์ชันที่ใช้การแสดงผลล่วงหน้าจะโหลดได้เร็วขึ้น 4.2 วินาที](https://web.dev/static/articles/prerender-with-react-snap/image/a-side-side-loading-comp-38a189328548.gif?authuser=6&hl=th)
เหตุใดจึงมีประโยชน์
ปัญหาด้านประสิทธิภาพที่สำคัญกับแอปพลิเคชันหน้าเว็บเดียวขนาดใหญ่คือผู้ใช้ต้องรอชุด 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 ที่สำคัญแทรกในบรรทัด
บทสรุป
หากคุณไม่ได้แสดงผลเส้นทางการแสดงผลฝั่งเซิร์ฟเวอร์ในแอปพลิเคชัน ให้ใช้ react-snap
เพื่อแสดงผล HTML แบบคงที่ให้กับผู้ใช้
- ติดตั้งเป็นทรัพยากร Dependency ของการพัฒนาและเริ่มต้นด้วยการตั้งค่าเริ่มต้นเท่านั้น
- ใช้ตัวเลือก
inlineCss
แบบทดลองเพื่อแทรก CSS ที่สำคัญในหน้าหากใช้งานกับเว็บไซต์ของคุณได้ - หากคุณใช้การแยกโค้ดในระดับคอมโพเนนต์ภายในเส้นทางใดก็ตาม โปรดระมัดระวังอย่าแสดงผลสถานะการโหลดให้กับผู้ใช้ล่วงหน้า
react-snap
README จะอธิบายเกี่ยวกับเรื่องนี้โดยละเอียดยิ่งขึ้น