אתם לא רוצים רינדור בצד השרת, אבל אתם עדיין רוצים לזרז את הביצועים של אתר React? כדאי לנסות את הרינדור מראש!
react-snap
היא ספרייה של צד שלישי שמעבדת מראש דפים באתר שלכם לקובצי HTML סטטיים. הפעולה הזו יכולה לשפר את זמני First Paint באפליקציה.
הנה השוואה של אותה אפליקציה עם ובלי עיבוד מראש שנטען מראש בחיבור 3G ובמכשיר נייד:
למה זה שימושי?
בעיית הביצועים העיקרית באפליקציות גדולות הכוללות דף יחיד היא שהמשתמש צריך להמתין עד שחבילות ה-JavaScript שמרכיבים את האתר יסיימו את ההורדה, לפני שיוכלו לראות תוכן אמיתי. ככל שהחבילות גדולות יותר, כך המשתמש יצטרך להמתין יותר זמן.
כדי לפתור את הבעיה, מפתחים רבים נוקטים בגישה של רינדור האפליקציה בשרת במקום להפעיל אותה רק בדפדפן. בכל מעבר של דף/נתיב, ה-HTML המלא נוצר בשרת ונשלח לדפדפן, וכך מפחית את זמני ה-FP, אבל עולה על זמן איטי יותר עד ל-First Byte.
עיבוד מראש הוא שיטה נפרדת שהיא פחות מורכבת מעיבוד באמצעות שרת, אבל היא גם מספקת דרך לשיפור זמני 'עיבוד ראשון' באפליקציה. דפדפן ללא GUI, או דפדפן ללא ממשק משתמש, משמשים ליצירת קובצי HTML סטטיים של כל מסלול במהלך זמן ה-build. לאחר מכן אפשר לשלוח את הקבצים האלה יחד עם חבילות ה-JavaScript שנחוצות לאפליקציה.
תגובה מהירה
react-snap
משתמש ב-Puppeteer כדי ליצור קובצי HTML שעברו עיבוד מראש של מסלולים שונים באפליקציה שלכם. כדי להתחיל, התקינו אותה כתלויה בפיתוח:
npm install --save-dev react-snap
לאחר מכן צריך להוסיף סקריפט postbuild
אל package.json
:
"scripts": {
//...
"postbuild": "react-snap"
}
הפעולה הזו תריץ באופן אוטומטי את הפקודה react-snap
בכל פעם build חדש של האפליקציות שנוצרו (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
כדי לעבד את רכיב התגובה הבסיסי (root) ישירות ל-DOM, המטרה היא לבדוק אם כבר קיימים צומתי צאצא כדי לקבוע אם תוכן HTML עובד מראש (או עובד בשרת). במקרה כזה, במקום זאת נשתמש ב-ReactDOM.hydrate
כדי לצרף מאזיני אירועים ל-HTML שכבר נוצר, במקום ליצור אותו מחדש.
בניית האפליקציה תיצור עכשיו קובצי HTML סטטיים כמטענים ייעודיים (payloads) לכל מסלול שנסרק. כדי לראות איך נראה המטען הייעודי (Payload) של HTML, לוחצים על כתובת ה-URL של בקשת ה-HTML ואז על הכרטיסייה Previews בכלי הפיתוח ל-Chrome.
Flash של תוכן ללא עיצוב
למרות ש-HTML סטטי מעובד באופן כמעט מיידי, הוא עדיין נשאר ללא עיצוב כברירת מחדל, דבר שעלול לגרום לבעיה בהצגת "הבהוב של תוכן ללא סגנון" (FOUC). זה בולט במיוחד אם משתמשים בספריית CSS-in-JS כדי ליצור סלקטורים, כי חבילת ה-JavaScript צריכה להסתיים לפני שאפשר יהיה להחיל סגנונות.
כדי למנוע זאת, ניתן להוסיף ישירות ל-<head>
של מסמך ה-HTML את ה-CSS הקריטי, או את הכמות המינימלית של ה-CSS הדרושה לעיבוד הדף הראשוני. react-snap
משתמש בספרייה אחרת של צד שלישי בחלק התחתון, minimalcss
, כדי לחלץ CSS קריטי לנתיבים שונים. כדי להפעיל את האפשרות הזו, מציינים את הפרטים הבאים בקובץ package.json
:
"reactSnap": {
"inlineCss": true
}
בתצוגה המקדימה של התשובה בכלי הפיתוח ל-Chrome תוכלו לראות עכשיו את הדף המעוצב עם טקסט קריטי של CSS.
סיכום
אם האפליקציה שלכם לא כוללת מסלולי רינדור בצד השרת, צריך להשתמש ב-react-snap
כדי לעבד מראש HTML סטטי למשתמשים.
- מתקינים אותו כתלויות בפיתוח ומתחילים רק עם הגדרות ברירת המחדל.
- אפשר להשתמש באפשרות הניסיונית
inlineCss
כדי להטמיע CSS קריטי אם הוא מתאים לאתר שלכם. - אם אתם משתמשים בפיצול קוד ברמת הרכיב בתוך מסלולים כלשהם, הקפידו לא לעבד מראש את מצב הטעינה למשתמשים שלכם. קובץ ה-README של
react-snap
מספק פרטים נוספים בנושא.