הבלוג של ינון פרק

טיפים קצרים וחדשות למתכנתים

מה עושים עם התלויות של התלויות ב node

20/07/2022

הנה טריק פשוט שעזר לי להתקין תלויות היום בפרויקט ואולי יעזור גם לכם. דמיינו רגע שיש לכם פרויקט שתלוי בספריה מסוימת בגירסה יחסית עדכנית שלה, ועכשיו אתם צריכים להוסיף ספריה אחרת לא כל כך מתוחזקת, או שמאיזושהי סיבה אתם צריכים להשתמש בגירסה ישנה של הספריה. לדוגמה הקובץ package.json הבא מכיל את גירסה 18 של ריאקט וגירסה יחסית ישנה של react-select:

{
  "name": "webapp-demo",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-select": "4.3.1"
  },
  "devDependencies": {
    "@types/react": "^18.0.15",
    "@types/react-dom": "^18.0.6",
    "@vitejs/plugin-react": "^2.0.0",
    "vite": "^3.0.0"
  }
}

אם תנסו לשים אותו בתיקיה ולהריץ npm install זה ייכשל, כי react-select גירסה 4.3.1 צריך את ריאקט 16 או 17, והפרויקט שלי משתמש בגירסה 18 של ריאקט. זאת הודעת השגיאה:

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: webapp-demo@0.0.0
npm ERR! Found: react@18.2.0
npm ERR! node_modules/react
npm ERR!   react@"^18.2.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^16.8.0 || ^17.0.0" from react-select@4.3.1
npm ERR! node_modules/react-select
npm ERR!   react-select@"4.3.1" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See /Users/ynonp/.npm/eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/ynonp/.npm/_logs/2022-07-19T12_28_29_781Z-debug-0.log

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

מה שמביא אותנו לטריק של היום - המילה overrides. עם מפתח overrides אני יכול לשנות את הגירסאות של התלויות של התלויות שלי. בדוגמה שלנו נוסיף את המפתח ל package.json:

{
  "name": "webapp-demo",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-select": "4.3.1"
  },
  "devDependencies": {
    "@types/react": "^18.0.15",
    "@types/react-dom": "^18.0.6",
    "@vitejs/plugin-react": "^2.0.0",
    "vite": "^3.0.0"
  },
  "overrides": {
    "react-select": {
      "react": "18.2.0",
      "react-dom": "18.2.0"
    }
  }
}

והכל מותקן בשלום.

בבדיקה מה הותקן אני יכול לראות:

$ npm ls react

webapp-demo@0.0.0 /Users/ynonp/tmp/blog/webapp-demo
├─┬ react-dom@18.2.0
│ └── react@18.2.0 deduped
├─┬ react-select@4.3.1
│ ├─┬ @emotion/react@11.9.3
│ │ └── react@18.2.0 deduped
│ ├─┬ react-input-autosize@3.0.0
│ │ └── react@18.2.0 deduped invalid: "^16.3.0 || ^17.0.0" from node_modules/react-input-autosize
│ ├─┬ react-transition-group@4.4.2
│ │ └── react@18.2.0 deduped invalid: "^16.3.0 || ^17.0.0" from node_modules/react-input-autosize
│ └── react@18.2.0 deduped
└── react@18.2.0

כלומר התקנו את ריאקט 18.2 בלי שגיאות ובלי לקטר, למרות ש react-select ביקש גירסה נמוכה יותר. (וכמובן אף אחד לא מבטיח שזה יעבוד, אבל ספציפית בריאקט יש סיכוי טוב שכן כי בדרך כלל יש תאימות טובה אחורה).

חדש ב Node 18 - תמיכה מובנית ב Fetch API

25/04/2022

גירסה 18 של נוד מביאה איתה לא מעט חידושים: התמיכה ב ES Modules השתפרה פלאים, הוסיפו מודול מובנה להרצת בדיקות יחידה, ונוספה תמיכה לשני ממשקי רשת מהדפדפן שהם Fetch API ו Web Streams API.

בפוסט זה אציג את השימוש ב Fetch API ב Node.

המשך קריאה

שימו לב: נוד קורא גם את ה gitignore שלכם כשמפרסמים חבילות

17/03/2022

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

מפה לשם אני מנסה לבנות את החבילה ולפבלש, ובחלון אחר מפעיל npm install כדי לראות שזה עובד.

החבילה עצמה היא פרויקט צד לקוח שבניה שלו מייצרת תיקיה בשם dist, ובחלון השני שמשתמש בחבילה יש קוד שעושה import מאותה dist.

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

ניסיון שני בבניה, שוב publish, שוב install ו... dist עדיין לא שם.

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

dist/

גיט לוג חשף שהיתה כוונה טובה מאחורי השורה הזאת - אין צורך להוסיף את כל תוצרי הבניה ל git. אבל היא באה עם באג: בלי קובץ .npmignore בתיקיה, באופן אוטומטי npm יתעלם מהקבצים ב .gitignore ולא יפרסם אותם עם החבילה שלכם.

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

בואו נכתוב שרת GraphQL ב Node.JS כדי לראות איך זה עובד

30/08/2021

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

בפוסט היום אני רוצה לכתוב שרת GraphQL ב Node.JS ו Express כדי לראות איך זה עובד. הפרויקט הוא API למערכת ניהול משימות שמאפשר לנו לראות את המשימות הפתוחות במערכת ולעדכן סטטוס "בוצע" של כל משימה.

העליתי את כל הקוד בפוסט לפרויקט דוגמה בגיטהאב בקישור:

https://github.com/ynonp/express-graphql-demo

המשך קריאה

איך שולחים ומקבלים הודעות בתור RabbitMQ מתוך שרת Node.JS Express

21/08/2021

כשאני כותב קוד מדי פעם אני נתקע על שטות שאני חושב שצריכה להיות מאוד ברורה. השטות של היום היתה RabbitMQ ובפרט איך לחבר אותו ל Express. הנה הקוד שבסוף עבד לי בצירוף כמה אילוצים ששווה לשים לב אליהם כשאתם מקודדים דברים דומים.

המשך קריאה

היום למדתי: התקנת חבילות אופליין עם Node.JS

26/10/2019

כשהמקום בדיסק הקשיח שלי מתחיל להיגמר אני עובר עם זכוכית מגדלת על כל הקבצים והתיקיות ומחפש מה אפשר למחוק, כי בתחושה שלי דיסק קשיח של חצי טרה צריך להספיק לפחות לכל החיים. בכל מקרה בתוך החיפוש מצאתי ספריה קטנה בתיקיית הבית שנקראת ~/.npm שתופסת לי היום קצת מעל ג'יגה.

מה שיותר מפתיע היה תוכן התיקיה: היא מכילה את כל החבילות שאי פעם התקנתי ובכל הגירסאות שלהן. זה כאילו מישהו לקח את כל תיקיות ה node_modules של העולם והדביק את הכל יחד לתוך תיקיה אחת. אז הלכתי לתיעוד ומסתבר שזה בדיוק מה ש npm עושה כל פעם שאנחנו מתקינים חבילה. עוד קצת חיטוט בתיעוד ומסתבר שאפשר להשתמש ב cache הזה כדי להפוך את ההתקנות שלכם להרבה יותר מהירות. העברת הדגל --offline ל npm install גורמת ל npm להתקין את הספריה מהמטמון המקומי בלי לבקר באינטרנט כלל.

הנה השוואת זמנים קטנה בשביל לעשות גם לכם חשק:

$ time npm install --save express
real    0m3.625s

$ time npm install --offline --save express
real    0m1.646s

עכשיו רק נשאר למצוא איך להגביל את גודל ספריית ~/.npm כדי שלא תתפוס לי את כל הדיסק.

גם בצד השרת טייפסקריפט עובדת לא רע בכלל

27/01/2019

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

המשך קריאה

הזמנה לוובינר - אבטחת מידע ב Node.JS

08/01/2019

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

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

המערכת לא באוויר אבל הקוד זמין בגיטהאב בקישור הזה:

https://github.com/ynonp/secure-code-livedemo-loby

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

זה דף הוובינר לפרטים והרשמה:

https://www.tocode.co.il/workshops/61

נתראה בחמישי, ינון

טיפ קצר: בואו נגדיר קבועים ב Node.JS

09/12/2018

הפקודה const מגדירה ערך בתור קבוע נכון? אז למה כל כך מסובך להשתמש בה נכון ב Node, ואיך אפשר להגדיר קבוע שקבצים בכל התוכנית יכירו אותו?

נתחיל עם מה שעובד - כל עוד אנחנו בקובץ יחיד אפשר להשתמש ב const כדי לתת שם לערך קבוע:

const MESSAGE_SIZE = 48;

ומכאן ועד סוף הקובץ לא משנה מה תעשו השם MESSAGE_SIZE תמיד יתייחס למספר הקבוע 48. אבל העסק מסתבך מהר מאוד כשאנחנו רוצים לשתף מידע בין מספר קבצים. נניח שהקובץ utils.js מגדיר הפעם את הקבוע ומייצא אותו:

// utils.js
const MESSAGE_SIZE = 48;
exports.MESSAGE_SIZE = MESSAGE_SIZE;

והקובץ app.js מייבא את הקבוע:

const { MESSAGE_SIZE } = require('./utils');
console.log(MESSAGE_SIZE);

זה עבד לא רע והדפיס 48, אבל הולך להישבר די בקלות. נסו לכתוב במקום את הקוד הבא ב app.js:

const utils = require('./utils');
utils.MESSAGE_SIZE = 999;

console.log(utils.MESSAGE_SIZE);

הקוד ידפיס 999 וגם כל קובץ אחר שיטען את הקבוע מ utils יקבל עכשיו את הערך 999. מסתבר שברגע שאנחנו עוברים להשתמש במנגנון ה exports מה שאנחנו בעצם מייצאים הוא אוביקט. המילה const לא מונעת שינויים בשדות של האוביקט וכך כל מי שרוצה יכול לשנות את ה"קבועים" שלנו.

מה אפשר לעשות? אז אומנם const לא תעזור לשמור על שדות של אוביקטים משינויים, אבל Object.freeze דווקא כן. אם נפעיל אותה לפני ה export נוכל לקבל קבועים של ממש.

החליפו את תוכן הקובץ utils.js עם הקוד הבא:

module.exports = Object.freeze({
  MESSAGE_SIZE: 48,
});

ועכשיו בלי לשנות את app אפשר להריץ אותו שוב ולקבל את ערך הקבוע 48. מספר זה לא ישתנה לא משנה מה נכתוב בקבצים שטוענים אותו.

תקשורת דו-כיוונית עם socket.io

24/11/2018

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

המשך קריאה