• בלוג
  • בשעה טובה, גם לנו יש Server Side Rendering (שוב)

בשעה טובה, גם לנו יש Server Side Rendering (שוב)

24/04/2020

לפני שנה בערך דפים באתר הזה התחילו לעלות לאט, ברמה שהתחילה להדאיג. לאחר בדיקה גיליתי שהאשמה במנגנון שנקרא Server Side Rendering. ביטלתי אותו אבל לא בשמחה והיום שמחתי להחזיר אותו אחרי התיקונים הרלוונטיים. הנה סיכום קצר של מה שקרה, מה שתוקן ומה שעובד היום, בתקווה שיעזור גם לכם להוסיף SSR בצורה חכמה לאתר שלכם.

1. מה זה Server Side Rendering

הרבה אנשים (ואני ביניהם) אוהבים לכתוב אתרים תוך שימוש ב Front End Frameworks. יש כמה פריימוורקים פופולריים, המרכזיים הם Angular, React ו Vue, אבל באמת שיש עוד הרבה. אתר זה כתוב ב React ורוב הזמן אני מרוצה מהבחירה.

הבעיה עם פריימוורקים היא שהקוד שנוצר אינו קוד HTML שדפדפן יכול להציג מיד, אלא קוד JavaScript שאומר לדפדפן איך לצייר את הדף. הפער הזה אומר שהדפדפן שלכם צריך לקרוא ולהריץ את כל קוד ה JavaScript של האתר כדי לבנות בעצמו את הדפים, לפני שאתם יכולים לראות דפים אלה. על מכשירים חלשים או ישנים תהליך זה יכול להאט את זמן טעינת האתר בצורה מורגשת.

מסיבה זו הומצא מנגנון שנקרא Server Side Rendering (או בקיצור SSR). הרעיון שאנחנו יכולים להריץ את קוד ה JavaScript בצד השרת, ולשלוח לדפדפן את התוצאה כלומר את דף ה HTML. כך דפדפנים לא צריכים להתאמץ ולהריץ JavaScript כדי להציג את העמוד. דפדפנים שיודעים להריץ JavaScript עדיין יריצו את קוד ה JavaScript של האתר כדי לטפל בכל האינטרקטיביות שקורית אחרי שהעמוד נטען, אבל בכל מקרה כולם יוכלו לראות את האתר יותר מהר מהרגע שהדף הגיע אליהם.

2. הבעיה עם Server Side Rendering, ואיך לעקוף אותה.

הבעיה עם SSR היא שאם השרת שלכם (שלי) צריך להפעיל את קוד ה JavaScript בשביל הלקוח, ויש 200 לקוחות שגולשים בו-זמנית באתר, אז השרת צריך לעשות עבודה של 200 מחשבים. בשלב מסוים העסק הזה מתחיל להכביד על השרת והזמן שהשרת משקיע בהרצת קוד ה JavaScript יוצא הרבה יותר ארוך מהזמן שנחסך לדפדפנים.

כאן בטוקוד זה היה הרגע שכיביתי את ה SSR.

אבל, יחד עם הכיבוי גם ידעתי שיש פיתרון: אם השרת יוכל "לזכור" את תוצאת הפעלת קוד ה JavaScript שהוא יצר בשביל גולש אחד, אפשר יהיה לשלוח את התוצאה המוכנה גם לשאר הגולשים במקום להריץ את הקוד 200 פעמים. כך אנחנו חוסכים עבודה לכולם וגם גורמים לאתר לעבוד הרבה יותר מהר.

הפיתרון הזה הוא לא טריוויאלי, שכן כל גולש כאן באתר מקבל גירסא קצת אחרת של האתר. ליתר דיוק, משתמשים רשומים מקבלים גישה לקורסים שלהם, ולכל משתמש יש קורסים אחרים וגם כל משתמש נמצא במקום אחר בקורסים.

לכן למרות שאי אפשר לעזור לכל הגולשים עם SSR, עדיין יש משהו שכן אפשר לעשות. לא כל מי שמגיע לאתר הוא מנוי, ואלה מכם שאינם עדיין מנויים כן רואים בדיוק את אותו דף. לכן אפשר יהיה להפעיל SSR רק עבור אורחים, לשמור ב Cache את תוצאת הרינדור ולהשתמש בה גם עבור האורחים האחרים.

3. צרות קטנות (או: מה קרה היום)

עם הכיוון הזה בראש והקורונה ברקע יצאתי לדרך כדי לבנות את המנגנון:

  1. מימוש Server Side Rendering ו Caching של התוצאה לאורחים.

  2. הגשת קוד JavaScript למנויים.

מבחינת קוד רובי זה נראה בערך כך:

<% if current_user.guest? %>
    <%# React Code Updated: 22/4/2020 15:25 %>
    <% cache [request.url, *@cache_keys] do %>
    <%= react_component('RouterApp', props: @appstate, prerender: true) %>
    <% end %>
<% else %>
    <%= react_component('RouterApp', props: @appstate, prerender: false) %>
<% end %>

הפקודה cache היא מילת המפתח בפיתרון. היא גורמת לשרת לזכור איך העמוד נראה לפי אוסף של Cache Keys. בפעם הבאה שגולש יגיע עם Cache Key זהה הוא יקבל בדיוק את אותו דף שכבר חושב במקום להפעיל את ה SSR פעם שניה (או עשירית).

אחרי השינוי גיליתי שני באגים בקוד ריאקט שכתבתי ששברו את ה SSR:

  1. מספר ספריות npm לא עבדו טוב מתוך node כשרצו על השרת. לא שברתי את הראש על זה וכשהיתה ספריה שלא עבדה פשוט החלפתי אותה באחת אחרת שעובדת ועושה בדיוק את אותו דבר.

  2. מנגנון SSR הרבה יותר רגיש מדפדפן ל Markup לא תקני. אם כותבים אלמנט p בתוך אלמנט p בקוד ריאקט רגיל אין בעיה, אבל בקוד שמתרנדר בצד השרת כל האלמנט פשוט נמחק. זה לקח לי איזה חצי שעה למצוא את זה ולתקן את כל ה Markup הלא תקני באתר.

4. מה הרווחנו

החל מהיום בצהריים יש Server Side Rendering לאורחים. זה אומר שאם אתם לא Signed In לאתר אתם תקבלו מיידית דף HTML שיוצג עוד לפני שהדפדפן שלכם סיים להוריד את כל קוד ה JavaScript, ואם ביטלתם את ה JavaScript בדפדפן עדיין תוכלו להיכנס לבלוג ולדפי הקורסים באתר.

מצד שני אם אתם מנויים לא תרגישו שום שינוי והדפדפן שלכם עדיין יצטרך לרנדר בעצמו את קוד ה JavaScript כדי לראות את העמודים (מצטער). הסיבה היא שאין טעם לבנות מנגנון SSR כשהדף נראה אחרת לכל גולש ואי אפשר לשמור את התוצאה ב Cache.