מה הסיפור עם הסולמית ביישומי עמוד יחיד?
תשתיות פיתוח עמוד-יחיד מודרניות משתמשות לפעמים בסימן סולמית כדי לדעת באיזה עמוד אנחנו נמצאים. מאיפה הגיע, למה צריך אותו והאם אפשר בלעדיו? טוב ששאלתם.
1. שתי בעיות עם יישומי עמוד יחיד
המעבר ליישומי Single Page Applications הביא איתו שיפור ביצועים במובן זה שעכשיו כשגולש עובר לעמוד חדש באפליקציה לא צריך לטעון את כל דפי ה HTML מהשרת ואפשר פשוט להציג את התוכן החדש. כאן בקודפן תוכלו לראות דמו פשוט המבוסס על React Router וממחיש תכונה זו:
הקוד עצמו פחות חשוב כאן מההתנהגות: לחיצה על Home מציגה את דף הבית ולחיצה על About מציגה את דף האודות.
שתי הבעיות שאנשים עשויים להיתקל בהן בפיתוח יישומים כאלה קשורים לקשר בין מה שרואים על המסך לבין הכתובת בשורת ה URL. בדרך כלל שינוי עמוד בדפדפן משפיע על כתובת ה URL, אבל אם שינוי העמוד מתבצע בצורה מזויפת דרך JavaScript השינוי עשוי שלא להשתקף ב URL או להשתקף שם בצורה לא מדויקת.
אי תאימות בין שורת ה URL לבין מה שאנחנו רואים על המסך עשויה להשפיע על חווית המשתמש בשני אופנים מרכזיים:
לחיצה על כפתור Back עשויה לא לעבוד או לעשות משהו שונה ממה שהמשתמש ציפה.
לחיצה על כפתור "טעינה מחדש" של הדף עשויה לא לעבוד.
ב JavaScript יש לנו שליטה מלאה על כתובת ה URL באמצעות מנגנון שנקרא History API. אנחנו יכולים בצורה תכנותית לגרום לדפדפן להאמין שמשתמש עבר עמוד עם הפקודה:
history.pushState({}, "Page Title", "page2.html");
הפקודה מקבלת פרמטר ראשון שנקרא State Object, פרמטר שני שהוא ה Title של העמוד החדש ופרמטר שלישי שהוא הנתיב של העמוד החדש. כל פעם שמשתמש חוזר אחורה יהיה Event בשם popstate ודרכו קוד JavaScript אחר יוכל לגשת לאוביקט זה. אני רוצה להתמקד בפרמטר השלישי דווקא ולשאול איזה ערכים כדאי לכתוב שם.
2. סולמית בתוך הנתיב
בדרך כלל תשתיות פיתוח עמוד יחיד ב JavaScript יודעות לטפל אוטומטית בלחיצה על כפתור Back של הדפדפן ולעשות את הדבר הנכון. טעינה מחדש של העמוד לעומת זאת זה סיפור אחר לגמרי.
הפרמטר השלישי ל pushState הוא הכתובת של העמוד החדש. בדוגמת הקודפן שהתחלנו איתה את הפוסט פרמטר זה יהיה מחרוזת ריקה בכניסה לעמוד הבית או המילה about בכניסה לעמוד האודות. זה אומר שאחרי שעברנו לעמוד האודות אם מישהו ינסה לטעון מחדש את העמוד הוא כנראה יקבל שגיאה. הדפדפן יגש לכתובת:
https://server.com/about
ולא ימצא שם כלום כי השרת לא יודע לטפל בגישה לנתיב זה.
לכן הרבה פעמים מתכנתים בוחרים להשתמש בסימן הסולמית כדי לגרום ל URL להיראות שונה עבור צד הלקוח אבל זהה עבור צד השרת. נתבונן ב-3 הנתיבים הבאים:
https://server.com/index.html
https://server.com/index.html#home
https://server.com/index.html#about
בכל תשתית צד שרת שתיקחו הנתיבים האלה יגיעו לאותו מקום. אפילו אם אתם מוותרים על תשתית צד שרת ופשוט בוחרים להשתמש בקובץ סטטי עדיין הכל בסדר ותקבלו בדיוק את אותו HTML ו JavaScript מכל שלושת הנתיבים. לכן סולמית בתוך הנתיב היא דרך ממש טובה ביישומי עמוד יחיד להבדיל בין הדפים השונים: ל JavaScript כל נתיב נראה אחרת ולכן אפשר להציג תוכן שונה לגולש בכל נתיב אבל לשרת כל הנתיבים מגיעים לאותו קובץ שנותן ל JavaScript לשבור את הראש מה להציג ותמיד שולח את אותו HTML, CSS ו JavaScript.
3. נתיבים ללא סולמית
תריצו עוד שנתיים קדימה בזמן ואתם מגיעים לעולם שבו גם צד השרת רוצה לקחת חלק במסיבה. מערכות רבות משתמשות כבר ב node.js בצד השרת והקוד שם יודע להריץ JavaScript בדיוק כמו הדפדפן. לכן מתכנתים רבים התחילו לשתף את הלוגיקה של מעברי דפים בין השרת ללקוח.
הרעיון הוא שגם השרת יידע שהגישה ל:
https://server.com/about
צריכה להוביל לאותו דף HTML עם כל קוד ה JavaScript וה CSS. אולי אפילו השרת יריץ כבר חלק מה JavaScript וישלח לדפדפן מידע שכבר עבר עיבוד ומתאים לדף הנוכחי (למשל אפשר לדמיין מצב שהשרת כבר פונה לאיזשהו API מרוחק ומביא את המידע ואז שולח לדפדפן את התוצאה יחד עם המידע מבסיס הנתונים).
בשביל להיפטר מהסולמית לכן יש להוסיף תמיכה בקוד צד השרת כך שפניה ישירה לנתיב שמופיע ב URL תמיד תעבוד. במינימום זה אומר לשלוח את אותו HTML, CSS ו JavaScript כתשובה לכל פניה מהדפדפן אבל ככל שהמערכות הופכות מורכבות כך חלק מפעולת העיבוד גם כן מתבצע בשרת ונשלח לדפדפן מידע כמעט מוכן להצגה.
4. אז מה עדיף?
כמו תמיד במקרים האלה - זה תלוי. אם אתם הולכים על מערכת ללא שרת שטוענת את כל המידע שלה מדף HTML יחיד כדאי להשתמש בכתובות עם סולמית וכך ברור לכולם שהמידע תמיד מגיע מאותו קובץ. באתרים אמיתיים ברשת ההעדפה של רוב המשתמשים היא לראות כתובות בלי סולמית ולכן שווה להתאמץ ולהטמיע את התמיכה במנגנון זה גם בצד השרת שלכם.