Menu

npm למתחילים: install, init, update וניהול תלויות

איך npm עובד בפועל: התקנת חבילות, init, תלויות פיתוח, עדכונים, ומודל החשיבה שמאחורי node_modules וקובץ ה-lock.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

מה npm בעצם

npm הוא שלושה דברים תחת שם אחד. הוא registry: מסד נתונים ציבורי ענק של חבילות JavaScript בכתובת npmjs.com. הוא כלי שורת פקודה שמגיע עם Node.js להתקנה וניהול של החבילות האלה. והוא מפרט (הפורמט של package.json) שמתאר מה פרויקט צריך.

כשמריצים npm install express, הכלי מדבר עם ה-registry, מוריד את express ואת כל מה שהיא תלויה בו, שם את הקבצים בתיקייה בשם node_modules, ורושם את החבילה ואת הגרסה שלה ב-package.json. זה כל המעגל.

אם Node.js מותקן אצלכם, npm כבר קיים. בדקו:

node --version
npm --version

אם שתי הפקודות מדפיסות גרסה, אתם מוכנים.

להתחיל פרויקט: npm init

כל פרויקט npm צריך package.json. זה המניפסט: הוא מפרט את שם הפרויקט, הגרסה, הסקריפטים והתלויות. הדרך המהירה ביותר ליצור אותו היא npm init -y, שמקבלת את כל ברירות המחדל:

mkdir my-app
cd my-app
npm init -y

זה כותב משהו כזה:

{
  "name": "my-app",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

בלי ה--y, npm מעביר אתכם על כל שדה באופן אינטראקטיבי. בכל מקרה, בסוף יש לכם package.json, הקובץ שכל השאר נתלה עליו. נסקור את השדות שלו בפירוט בעמוד הבא.

התקנת חבילה

ברגע שיש package.json, מתקינים חבילה עם npm install (או בקיצור npm i):

npm install lodash

קורים שלושה דברים:

  1. npm מוריד את lodash ואת התלויות שלה לתוך node_modules/.
  2. הוא מוסיף "lodash": "^4.17.21" (או הגרסה העדכנית ביותר) לסעיף dependencies ב-package.json.
  3. הוא כותב package-lock.json שמתעד את הגרסאות המדויקות של כל חבילה בעץ.

עכשיו אפשר להשתמש בה:

הקריאה ל-require (או import בפרויקט ESM) מוצאת את החבילה על ידי חיפוש בתוך node_modules. לא כותבים נתיב: מנגנון פענוח המודולים של Node מטפל בזה.

dependencies מול devDependencies

לא כל חבילה נחוצה כשהאפליקציה רצה ב-production. frameworks לבדיקות, linters ו-bundlers חשובים רק בזמן פיתוח. מתקינים אותם עם --save-dev (או -D):

npm install --save-dev jest
npm install -D eslint prettier

הן נכנסות ל-devDependencies במקום ל-dependencies:

{
  "dependencies": {
    "lodash": "^4.17.21"
  },
  "devDependencies": {
    "jest": "^29.7.0",
    "eslint": "^8.57.0",
    "prettier": "^3.2.5"
  }
}

בשרת production, npm install --omit=dev מדלג לגמרי על סעיף הפיתוח, וההתקנה יוצאת קטנה ומהירה יותר. לחלק נכון חשוב יותר ממה שנראה: webpack שנשכח ב-dependencies מנפח כל deploy ל-production.

להתקין הכול בבת אחת

כשעושים clone ל-repo שכבר יש בו package.json, לא מפרטים כל חבילה. פשוט מריצים:

npm install

בלי ארגומנטים, npm קורא את package.json (ומכבד את הגרסאות המדויקות ב-package-lock.json) ומתקין את כל העץ לתוך node_modules. זה הדבר הראשון שמריצים על כל checkout חדש.

זו גם הסיבה ש-node_modules שייכת ל-.gitignore. אפשר לשחזר אותה מקובץ ה-lock, היא ענקית, והיא משתנה בכל פעם שמישהו מריץ npm install. עשו commit ל-package.json ול-package-lock.json, ותנו לכל השאר לייצר את node_modules בעצמם.

עדכון חבילות

npm outdated מראה מה מפגר:

npm outdated

תראו טבלה עם העמודות Current, Wanted ו-Latest. Wanted היא הגרסה החדשה ביותר שהטווח ב-package.json מאפשר (עבור ^4.17.21, כל מה שמתחת ל-5.0.0). Latest היא הגרסה החדשה ביותר שפורסמה, שעשויה להיות גרסה ראשית שעוד לא בחרתם לעבור אליה.

לעדכון בתוך הטווח המותר:

npm update

כדי לקפוץ לגרסה העדכנית באמת, כולל מעבר בין גרסאות ראשיות, מתקינים את החבילה שוב עם @latest:

npm install lodash@latest

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

הסרה

הסרת חבילה היא הפעולה ההפוכה:

npm uninstall lodash

זה מסיר אותה מ-node_modules ומוחק את הרשומה מ-package.json. הוסיפו -D אם זו הייתה תלות פיתוח (npm מבין את זה בכל מקרה, אבל להיות מפורשים חוסך הפתעות בסקריפטים).

גלובלי מול מקומי

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

npm install -g typescript
npm install -g http-server

התקנה גלובלית שמה את הכלי במיקום ברמת המערכת ואת ה-bin שלו ב-PATH, כך שאפשר להריץ tsc או http-server מכל תיקייה. אבל התקנות גלובליות לא נרשמות לכל פרויקט, והן עלולות לצאת מסנכרון בין מחשבים.

דרך ביניים טובה יותר לפקודות חד-פעמיות היא npx, שמגיע עם npm:

npx create-react-app my-app
npx prettier --write .

npx מריץ חבילה בלי להתקין אותה גלובלית: הוא מביא אותה לפי דרישה, מריץ אותה, וזהו. לכלים שמשתמשים בהם פעם אחת, זה נקי יותר מהתקנה גלובלית קבועה.

דף עזר מינימלי

הפקודות שתשתמשו בהן בפועל ביום-יום:

npm init -y                     # create package.json
npm install                     # install everything in package.json
npm install <pkg>               # add a runtime dependency
npm install -D <pkg>            # add a dev dependency
npm install -g <pkg>            # install a CLI tool globally
npm uninstall <pkg>             # remove a dependency
npm outdated                    # see what's out of date
npm update                      # update within allowed ranges
npm install <pkg>@latest        # jump to the newest version
npm run <script>                # run a script from package.json
npx <pkg>                       # run a package without installing it

זה רוב npm. את השאר, פרסום חבילות, workspaces, scoped packages, תלמדו כשתצטרכו.

מה באמת יושב ב-node_modules

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

קובץ ה-lock (package-lock.json) מתעד את הגרסה המדויקת שנבחרה לכל אחת מהחבילות האלה. זה מה שהופך builds לניתנים לשחזור: שני מפתחים שמריצים npm install מאותו קובץ lock מקבלים עצים זהים עד הבית, גם בהפרש של חודשים.

התייחסו ל-node_modules כאל פלט שנוצר אוטומטית. לעולם אל תערכו קבצים בתוכה: השינויים ייעלמו בפעם הבאה שמישהו יתקין.

הבא בתור: package.json

package.json הוא הקובץ ש-npm ממשיך לקרוא ולכתוב מחדש מאחורי הקלעים. היכרות עם השדות שלו, scripts, main, type, טווחי גרסאות, engines, היא מה שהופך את npm מקופסה שחורה למשהו שאתם שולטים בו. זה הנושא הבא.

שאלות נפוצות

מה זה npm?

npm הוא מנהל החבילות המובנה של Node.js. הוא מגיע עם Node, מארח registry ציבורי ענק של חבילות JavaScript, ומספק כלי שורת פקודה להתקנה, עדכון ופרסום שלהן. כשמריצים npm install lodash, npm מוריד את lodash מה-registry לתוך node_modules ורושם אותו ב-package.json.

מה ההבדל בין dependencies ל-devDependencies?

dependencies הן חבילות שהאפליקציה צריכה כדי לרוץ ב-production, כמו express או react. devDependencies נחוצות רק בזמן פיתוח או build: test runners, bundlers, linters. את האחרונות מתקינים עם npm install --save-dev <pkg> (או -D). ב-production, npm install --omit=dev מדלג על devDependencies.

האם לעשות commit ל-node_modules ב-git?

לא. node_modules יכולה בקלות להגיע למאות מגה-בייט, ואפשר לשחזר אותה במלואה מ-package.json ועוד package-lock.json. הוסיפו אותה ל-.gitignore ועשו commit לקובץ ה-lock במקום. כל מי שעושה clone ל-repo מריץ npm install ומקבל בדיוק את אותו עץ תלויות.

מה ההבדל בין התקנה גלובלית למקומית ב-npm?

התקנה מקומית (npm install <pkg>) שמה את החבילה בתוך node_modules של הפרויקט ורושמת אותה ב-package.json. התקנה גלובלית (npm install -g <pkg>) מתקינה אותה ברמת המערכת כולה, בדרך כלל בשביל כלי שורת פקודה שרוצים שיהיו זמינים בכל מקום. העדיפו התקנה מקומית לתלויות של פרויקט, כדי שהגרסאות יישארו נעולות לכל פרויקט בנפרד.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל