טיפ נקסט: שימו לב ל import-ים
ב next.js בגירסה ה Page Router יש לנו שלוש אפשרויות לטעון ספריות חיצוניות, ואני חושש שההבדל ביניהן לא תמיד מספיק ברור.
טיפים קצרים וחדשות למתכנתים
ב next.js בגירסה ה Page Router יש לנו שלוש אפשרויות לטעון ספריות חיצוניות, ואני חושש שההבדל ביניהן לא תמיד מספיק ברור.
בואו נראה דוגמה פשוטה מ vue לצמצום כפל קוד ואז ננסה לראות מה דעתנו על השינוי. אני מתחיל עם משתנה בשם seconds ושני משתנים מחושבים בשם minutes ו hours:
const seconds = ref(0);
const minutes = computed(() => {
get() { return seconds / 60},
set(minutes) { seconds.value = minutes * 60}
});
const hours = computed(() => {
get() { return hours / 3600},
set(hours) {seconds.value = hours * 3600}
})
ואז אני שם לב ש minutes ו hours בעצם חושבו באותה צורה אז אני מארגן מחדש את הקוד:
function deriveTime(start: Ref<number>, factor: number) {
return computed({
get() { return Number((start.value / factor).toFixed(2)) },
set(newValue) { start.value = newValue * factor }
})
}
const seconds = ref(0);
const minutes = deriveTime(seconds, 60);
const hours = deriveTime(seconds, 3600);
יותר מזה, מאחר ו deriveTime לא באמת קשורה לקומפוננטה אני יכול להעביר אותה לקובץ אחר ואז יש לי רק:
const seconds = ref(0);
const minutes = deriveTime(seconds, 60);
const hours = deriveTime(seconds, 3600);
והשאלה - איזה API טוב יותר? כמה מחשבות:
הפונקציה deriveTime משנה התנהגות. בזה שהיא מחביאה קריאה ל computed היא מחזיקה בתוכה מטען סמנטי משמעותי. כל מי שיקרא את הקוד יצטרך לדעת שפונקציה זו מחזירה ערך מחושב ושומרת על ריאקטיביות, ושאת הערך המחושב הזה אפשר גם לשנות.
במילים אחרות החוזה של פונקציית deriveTime עם הקוד החיצוני כולל יותר התחייבויות ממה שרואים ברשימת הפרמטרים.
אם הפונקציה נמצאת בשימוש בהרבה מקומות בקוד המערכת יש הגיון להוסיף לה את המטען הסמנטי הזה. ממילא כל מי שיקרא את הקוד צפוי להכיר אותה. ככל שהיא פחות נמצאת בשימוש היא עלולה לבלבל.
פיתרון טוב יהיה להוסיף תיעוד באתר הקריאה שמסביר מה קורה פה, משהו כזה:
const seconds = ref(0);
// create reactive modifiable computed refs for other time units:
const minutes = deriveTime(seconds, 60);
const hours = deriveTime(seconds, 3600);
מצד שני ככל שההסבר בתיעוד יותר ארוך אולי עדיף להישאר עם הקוד המקורי.
פיתרון ביניים נוסף שיכול לעזור כאן הוא להעביר רק את יצירת האוביקט לפונקציה אבל להשאיר את הקריאה ל computed באתר הקריאה כלומר:
const seconds = ref(0);
const minutes = computed(deriveTime(seconds, 60));
const hours = computed(deriveTime(seconds, 3600));
כתיבה כזאת משאירה את "מילת המפתח" computed במקום בולט וכך אנחנו יודעים מה אנחנו יוצרים. עדיין גם גירסה זאת מסתירה את העובדה שהאוביקט כולל גם getter וגם setter ולכן אפשר לשנות את הדקות והשעות.
הוצאת קוד לפונקציה כדי למנוע חזרה היא הרבה פעמים רעיון טוב. היא מאפשרת תחזוקה טובה יותר של הקוד ותיקון בעיות רק במקום אחד. מצד שני כשאנחנו מסתירים קריאה לפונקציות ליבה של הפריימוורק בתוך פונקציית עזר שלנו התוצאה עלולה להיות קוד מבלבל יותר ורק להקשות על התחזוקה.
מה דעתכם? במצב כזה הייתם משתמשים בפונקציית עזר, נשארים עם הקוד הכפול או בוחרים פיתרון אחר?
חוץ משיחות, ChatGPT גם יודע לחשב משהו שנקרא Embedding לכל טקסט שניתן לו. אמבדינג זה בעצם וקטור של מספרים שמייצג איפה במוח של ChatGPT הטקסט הזה יושב, כי אפשר לדמיין את המוח של ChatGPT בתור מרחב רב מימדי של טקסטים. בעזרת וקטור כזה אפשר לפעמים למצוא דברים שקשורים אחד לשני, כי הם כנראה יהיו "קרובים" באותו מרחב רב מימדי.
בפוסט היום הלכתי לנסות לחשב Embeddings ולראות אם זה יעזור לי לזהות פוסטים מהבלוג שקשורים לפוסט מסוים. המסקנה אינה חד משמעית אבל אני מקווה שהדרך תהיה מעניינת.
אחד המנגנונים החמודים של Vue הוא ה Directives שמאפשרים לכתוב פחות קוד בקוד התבנית ולקחת חלקים של קוד שמשפיעים על ה DOM כדי להשתמש בהם בכמה מקומות. בשביל המשחק בואו ננסה לבנות משהו דומה בריאקט.
מישהו ברדיט שאל- יש לנו אלפי בדיקות אנזים לפרויקט ריאקט ואני רואה שאנזים כבר לא נתמך ורק בגלל הבדיקות אנחנו תקועים עם גירסה ישנה של ריאקט. מה עושים?
ואותה שאלה חוזרת כל הזמן ובאינסוף גירסאות ... מה עושים עם אפליקציית אנגולר1? מה יקרה עם אפליקציית ה next.js שלי במעבר ל App Router? מה עושים עם כל הקלאסים כשיצאו React Hooks? מה עושים עם אתר הפלאש? הסילברלייט? ה Java Applet?
ובדיקות זה עוד החלק הקל. לא נעים אבל אפשר למחוק את כל הבדיקות ולהתחיל לכתוב מחדש ב React Testing Framework. לפעמים צריך לעדכן קוד ולפעמים לכתוב מוצר חדש מאפס.
יש שיגידו ששינויים כאלה הם הסיבה לכתוב Micro Services. אני לא בגישה הזאת. שינויים דרסטיים (פריימוורק שלם לא עובד יותר) אינם פתאומיים, וכמעט תמיד אפשר לשכתב דברים בהדרגה או רק חלק מהמוצר. בסוף אנחנו חיים בעולם דינמי וכדאי לזכור החדשים נוצרו מסיבה - הרבה פעמים כתיבה מחדש של אותו קוד עם הכלים החדשים תהיה הרבה יותר מהירה מהכתיבה בפעם הראשונה, גם בגלל שאנחנו יודעים יותר טוב מה לעשות וגם בגלל שהכלים החדשים פשוטים וטובים יותר.
הרבה אנשים מדברים על עקומת הלמידה של ריאקט בהשוואה ל Vue ויש בזה משהו. נכון לריאקט 18 (כלומר לפני ש Suspense יהיה דבר גדול ולפני use והבעיות שלו), האתגר הכי גדול עם ריאקט היה useEffect. בואו נראה דוגמה קצרה של אפקט בהשוואה בין שתי הספריות כדי להבין קצת את הרוח והייחודיות של כל אחת.
הערך sticky של מאפיין position ב CSS יכול לחסוך הרבה כאב ראש כשרוצים לבנות טבלה עם כותרות דביקות - כלומר טבלה עם פסי גלילה בה שורת הכותרת נשארת תמיד למעלה (כמו באקסל) כשגוללים למטה כדי שאפשר יהיה לראות את שמות העמודות, ובאותו אופן העמודה הראשונה תישאר תמיד על המסך כשנגלול הצידה. זה הקוד בקצרה:
thead {
position: sticky;
top: 0;
z-index: 2;
}
th:first-child, td:first-child {
position: sticky;
left: 0;
}
td:first-child {
background-color: white;
}
th {
background-color: #f2f2f2;
}
בואו נעבור על כל המאפיינים:
המאפיין position: sticky גורם לאלמנט "להידבק" למיקום מסוים אם גלילה תגרום לו לצאת מהמסך. זה בדיוק האפקט שאנחנו רוצים לכותרות של הטבלה. ל thead הגדרתי שיידבק לחלק העליון בעזרת top וכל td שהוא ילד ראשון, כלומר כל העמודה הראשונה, נדבקת לצד שמאל.
הגדרת z-index על thead קבעה ששורת הכותרת העליונה תופיע מעל עמודת הכותרת וכך שם העמודה הראשונה לא מוסתר בגלילה למטה על ידי הערכים של העמודה.
אלמנטים שמוגדרים בתור sticky יופיעו "מעל" אלמנטים אחרים ולכן צריכים הגדרת צבע רקע כי אחרת נוכל לראות את הטקסט של השורות כשהן עוברות "מתחת" לשורת הכותרת או של העמודות כשהן עוברות "מתחת" לעמודת הכותרת.
העליתי לקודפן את הקוד המלא עם כל ה CSS וה HTML של הטבלה מוזמנים לשחק עם זה בקישור: https://codepen.io/ynonp/pen/zYgWKOM
או מוטמע כאן:
כואב לשים לב שהרבה בעיות אבטחת מידע הן בעצם בעיות תיאום ציפיות. היה מספיק שסטראבה היתה מציגה פופ-אפ לפני שיתוף מסלול שאומר משהו כמו-
אתה עומד לשתף מידע על מסלול ריצה שביצעת עם האינטרנט. שים לב: כל בן אדם אחר שרץ את אותו מסלול יוכל לראות את הפרטים שלך ואת כל המסלולים האחרים בהם רצת. האם אתה בטוח שאתה רוצה להמשיך?
ואולי בעצם איש ה Product שהיה מנסח כזאת הודעה היה מבין ששיתוף כזה הוא שבור וכולל בעיית אבטחה מובנית וכך היה נחסך מאיתנו פיצ'ר ריגול מיותר.
אני יודע אתם כבר לא משתמשים ב Apache, יש לכם nginx או שאתם שמים את הפרויקטים שלכם על vercel או AWS ומי בכלל מתחזק שרתים בימינו. נו, אני צוחק. המון אנשים מתחזקים שרתים, ובהרבה מהם רץ עדיין Apache. ואחת הבעיות עם Apache היא שהודעות השגיאה שלו לא תמיד קיימות או לא מדויקות.
אז אם לדוגמה יש לי קובץ קונפיגורציה ל Site עם טעות, לפעמים אפאצ'י יסרב לעלות. לפעמים הוא יספר פרטים על הטעות ולפעמים הוא פשוט יעביר את התנועה שנשלחה ל Site הזה ל Site אחר עם קונפיגורציה יותר גנרית.
דרך אחת לקבל יותר אינפורמציה על Apache היא הפקודה: apache2ctl -S
. הפלט מהשרת שלי נראה בערך כך:
AH00548: NameVirtualHost has no effect and will be removed in the next release /etc/apache2/sites-enabled/002-tocode.co.il.conf:1
VirtualHost configuration:
*:443 is a NameVirtualHost
default server tocode.co.il (/etc/apache2/sites-enabled/002-tocode.co.il.conf:8)
port 443 namevhost tocode.co.il (/etc/apache2/sites-enabled/002-tocode.co.il.conf:8)
port 443 namevhost www.tocode.co.il (/etc/apache2/sites-enabled/002-tocode.co.il.conf:27)
*:80 is a NameVirtualHost
default server tocode.co.il (/etc/apache2/sites-enabled/002-tocode.co.il.conf:3)
port 80 namevhost tocode.co.il (/etc/apache2/sites-enabled/002-tocode.co.il.conf:3)
וזה מראה לנו איזה Host-ים יש לנו על השרת, באיזה שמות מטפל כל Host והכי חשוב באיזה קובץ קונפיגורציה כל Host הוגדר. המשך הפלט מראה עוד נתוני debug שלי היו פחות חשובים. נסו את זה על השרתים שלכם וספרו אם למדתם משהו חדש או מצאתם משהו מיותר.
כבר כמה ימים שאני משחק עם קוד כדי להוריד תמונות מויקיפדיה בשביל בוט מילון שאני כותב, וכמו הרבה פעמים בפרויקטי צד אני אוהב לבחור טכנולוגיות שמעניינות אותי כדי לראות איך זה עובד בעולם האמיתי. הפעם לקחתי את דינו ורציתי לראות אם אני יכול להשתמש ב Deno2 לפרויקט ובעיקר מה יהיו הקשיים. סיכום הניסוי בפוסט כאן.