פיתוח יישומי Front End בצד שרת

17/01/2021

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

1. ריילס ו Stimulus Reflex

הספריה StimulusReflex בריילס מאפשרת לפתח יישומי צד-לקוח עשירים ללא כתיבת JavaScript (או עם כתיבת הרבה פחות JavaScript ממה שהיינו מצפים). הארכיטקטורה שלה פשוטה ונשמעת במבט ראשון קצת לא הגיונית:

  1. כל לקוח שמתחבר לאתר פותח Web Socket לשרת.

  2. כשלקוח מבצע פעולה אנחנו שולחים את המידע המעניין על הפעולה לשרת דרך ה Web Socket, השרת מטפל באירוע ומחזיר קוד HTML חדש ללקוח.

  3. הלקוח מחליף את ה HTML שהיה לו במה שהגיע מהשרת.

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

2. דוגמה 1 - מונה לחיצות

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

# file: app/reflexes/counter_reflex.rb

class CounterReflex < ApplicationReflex
  def increment
    @count = element.dataset[:count].to_i + 1
  end
end

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

בשביל להשתמש ברפלקס אני מגדיר את המבנה הבא בתוך ה HTML שלי בקובץ ה View:

<div id="counter-demo" data-reflex-root="#counter-demo">
  <button
    data-reflex="click->Counter#increment"
    data-count="<%= @count %>"
  >

    Click Here
  </button>
  <p>You clicked <%= @count.to_i %> times</p>
</div>

יש לנו כפתור עם מאפיין בשם data-reflex שמגדיר איזה רפלקס ייקרא כשלוחצים עליו ומאפיין data-count שנשלח לרפלקס. אני משתמש במשתנה @count בכל הבלוק שבתוך אלמנט counter-demo ולכן הגדרתי את counter-demo בתור שורש עץ הרפלקס. באופן אוטומטי אחרי ביצוע הרפלקס ריילס יבנה מחדש את ה HTML וישלח אותו לצד הלקוח, וקוד JavaScript בצד הלקוח יחליף את האלמנטים הרלוונטים בתוך data-reflex-root בערכים החדשים שלהם. התוצאה כמו שאתם בטח מדמיינים כבר היא מונה לחיצות שמציג כפתור ואחריו פיסקה שמספרת כמה פעמים לחצו על הכפתור.

3. דוגמה 2 - השלמה אוטומטית

בגלל שקוד הטיפול באירוע רץ בצד השרת יש לי שם גישה מלאה לבסיס הנתונים ולכל המידע של השרת. הדוגמה הבאה ממחישה את היופי בגישה באמצעות רכיב של השלמה אוטומטית. נתחיל עם קוד צד השרת:

class ExampleReflex < ApplicationReflex
  def autocomplete
    search_text = element.value

    @options = User.where("name like 'search_text%'").pluck(:name)
  end
end

בגלל שאנחנו רצים בצד שרת אין בעיה לגשת לבסיס הנתונים ולמשוך משם את כל המשתמשים שהשם שלהם מתחיל בטקסט שכתוב ב input. שומרים את הרשימה במשתנה @options וב HTML אפשר לכתוב את הקוד הבא:

<div id="ajax-autocomplete-demo" data-reflex-root="#autocomplete-options">
  <input type="text" data-reflex="input->Example#autocomplete" list="autocomplete-options" />
  <datalist id="autocomplete-options">
    <%= @options&.each do |val| %>
      <option value="<%= val %>" />
    <% end %>
  </datalist>
</div>

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

4. מה הלאה

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

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

בעולמות מקבילים לריילס קונספט דומה כבר קיים בפיניקס (נקרא LiveView), ב Django שם זה נקרא Reactor וכבר התחילו לדבר על זה בעולם של ריאקט עם משהו שנקרא Server Components. האם אנחנו הולכים לראות חזרה לצד השרת בקרוב? עדיין קשה לדעת. אבל הפוטנציאל מבחינת שיפור בזמני טעינה, גודל האתרים ופשטות הפיתוח בהחלט נשמע מלהיב.