קובץ ה-Manifest של פרויקט Node
לכל פרויקט Node.js יש package.json בתיקיית השורש. זה קובץ JSON פשוט שמתאר את הפרויקט: השם שלו, הגרסה שלו, במה הוא תלוי, אילו פקודות הוא חושף. זה הקובץ ש-npm קורא בכל פעם שהוא עושה משהו. מחקו אותו, ול-npm אין מושג מה הפרויקט שלכם.
הדרך המהירה ביותר ליצור אחד היא npm init:
npm init -y
הדגל -y מדלג על השאלות ומקבל את ברירות המחדל. בסוף תקבלו משהו כזה:
{
"name": "my-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
זה השלד הבסיסי. רוב השדות האלה לא עושים הרבה בפני עצמם: הם נהיים שימושיים כשמוסיפים תלויות וסקריפטים.
Dependencies מול devDependencies
שני שדות עושים כמעט את כל העבודה הקשה: dependencies ו-devDependencies. שניהם הם מיפויים משמות חבילות לטווחי גרסאות.
החלוקה חשובה מסיבה אחת: dependencies הן חבילות שהקוד שלכם צריך כדי לרוץ. devDependencies הן חבילות שצריך רק בזמן פיתוח: כלי הרצת בדיקות, linters, כלי בנייה, בודקי טיפוסים. כשמישהו מתקין את החבילה שלכם כתלות של החבילה שלו, npm מוריד את ה-dependencies שלכם ומדלג על ה-devDependencies.
npm מעדכן את השדות האלה אוטומטית. npm install express מוסיף שורה ל-dependencies. npm install --save-dev vitest מוסיף שורה ל-devDependencies. כמעט אף פעם לא עורכים אותם ידנית.
טווחי גרסאות: ^, ~ ומדויק
מחרוזות הגרסה האלה כמו ^4.19.0 אינן גרסאות מדויקות: הן טווחים. npm פועל לפי semver, שמחלק גרסאות ל-MAJOR.MINOR.PATCH:
- הקפצות של MAJOR שוברות תאימות לאחור.
- הקפצות של MINOR מוסיפות יכולות אבל לא שוברות כלום.
- הקפצות של PATCH מתקנות באגים.
שני האופרטורים שתראו בכל מקום:
"express": "^4.19.0" // >= 4.19.0 and < 5.0.0 (any 4.x.x at or above 4.19.0)
"express": "~4.19.0" // >= 4.19.0 and < 4.20.0 (any 4.19.x at or above 4.19.0)
"express": "4.19.0" // exactly 4.19.0
^ היא ברירת המחדל ש-npm משתמש בה כשמתקינים חבילה. היא סומכת על כך שהקפצות minor ו-patch יישארו תואמות. ~ שמרנית יותר: רק עדכוני patch. גרסה לבד נועלת בדיוק.
המלכודת: "מה שהתקנתי עכשיו" ו"מה שהטווח מתיר" אינם אותו דבר. אם התקנתם היום express@4.19.0 וחבר צוות מתקין את הפרויקט שלכם בעוד חודש, ^4.19.0 עשוי להיפתר ל-4.19.5. כאן נכנס לתמונה package-lock.json: הוא מתעד את הגרסאות המדויקות שנבחרו, כך שכולם מקבלים את אותו עץ. עשו לו commit.
סקריפטים: ממשק הפקודות של הפרויקט
השדה scripts הוא המקום שבו מגדירים קיצורי דרך לפקודות נפוצות. כל מה ששמים שם אפשר להריץ עם npm run <name>:
כמה דברים שכדאי לדעת על סקריפטים:
npm start,npm testוקומץ שמות נוספים עובדים בלי מילת המפתחrun. כל השאר צריכיםnpm run <name>.- סקריפטים רצים ב-shell שבו
node_modules/.binנמצא ב-PATH, כך שאפשר לקרוא ישירות לקבצי הרצה של חבילות מותקנות."test": "vitest"עובד גם כש-vitestלא מותקן גלובלית. - אפשר לשרשר סקריפטים:
"build": "npm run lint && npm run compile". השתמשו ב-&&עבור "הרץ ברצף, עצור בכישלון". - סקריפטים בשם
pre<name>ו-post<name>רצים אוטומטית. אם יש לכםprebuild, הוא ירוץ לפניbuildבלי שום חיווט נוסף.
הסקריפטים הם ממשק הפקודות של הפרויקט. package.json טוב אומר שתורם חדש יכול לעשות clone, להריץ npm install, ואז npm run dev / npm test בלי לקרוא ויקי.
נקודות כניסה: main, exports, type
השדות האלה אומרים ל-Node (ול-bundlers) איך לטעון את החבילה שלכם.
typeקובע איך קבצי.jsמפוענחים."module"פירושו ESM (import/export). השמיטו אותו או הגדירו"commonjs"עבור CommonJS (require). ראו את המסמך על CommonJS מול ESM לתמונה המלאה.mainהיא נקודת הכניסה הישנה: למהrequire("my-lib")נפתר. כלים ישנים עדיין מכבדים אותה.exportsהוא התחליף המודרני והקפדני יותר. הוא מגדיר בדיוק אילו קבצים הצרכנים יכולים לייבא ותחת איזה תת-נתיב. אם קובץ לא מופיע כאן, הייבוא שלו נכשל, וזו תכונה ולא באג. אתם שולטים ב-API הציבורי.
אם אתם רק בונים אפליקציה (ולא מפרסמים חבילה), type הוא כנראה היחיד מבין השדות האלה שמעניין אתכם.
package.json מציאותי
אם מחברים הכול, כך בערך נראה package.json של אפליקציית Node קטנה בפועל:
שימו לב ל-engines.node. הוא מייעץ בלבד: npm מזהיר (או נכשל עם engine-strict) אם גרסת ה-Node של המשתמש לא תואמת. היגיינה טובה לכל דבר שאתם מפרסמים.
שדות ששווה להכיר
עוד כמה שדות שתיתקלו בהם:
private: true: מונע מכם לפרסם בטעות את החבילה ב-npm. הגדירו אותו בכל פרויקט שלא נועד לפרסום.license: מזהה SPDX כמו"MIT"או"ISC". חשוב לכל דבר ציבורי.repository,bugs,homepage: מוצגים בעמוד החבילה ב-npm registry.bin: אם החבילה שלכם כוללת CLI, מפו כאן שמות פקודות לקבצי סקריפט. אחרי ההתקנה, אפשר להריץ את הפקודות האלה.workspaces: עבור monorepos; אומר ל-npm להתייחס לתת-תיקיות כחבילות מקושרות.
לא צריך את כולם. צריך את הנכונים למה שאתם עושים.
מלכודות נפוצות
קומץ דברים שמפילים אנשים:
- עשיית commit ל-
node_modules. אל תעשו את זה. הוסיפו אותה ל-.gitignore.package.jsonיחד עםpackage-lock.jsonמספיקים כדי שכל אחד יבנה אותה מחדש עםnpm install. - אי-עשיית commit ל-
package-lock.json. כן עשו לו commit. בלי קובץ הנעילה, "אצלי זה עובד" הופך לאפשרות אמיתית, כי טווחי semver יכולים להיפתר לגרסאות שונות לאורך זמן. - הכנסת תלויות זמן ריצה ל-
devDependencies. האפליקציה שלכם עשויה לעבוד מקומית כי תלויות הפיתוח מותקנות, ואז להישבר ב-production שבו מדלגים עליהן. אם הקוד שאתם שולחים משתמש בחבילה, מקומה ב-dependencies. - עריכת גרסאות ידנית בלי התקנה מחדש. שנו גרסה ב-
package.jsonוהריצוnpm install, אחרתnode_modulesוקובץ הנעילה יוצאים מסנכרון.
הבא בתור: סביבת הריצה של Node
package.json אומר ל-Node מה הפרויקט שלכם. סביבת הריצה של Node מחליטה איך הוא רץ: פתרון מודולים, מודולים מובנים, משתנים גלובליים, ולולאת האירועים מתחת למכסה המנוע. זה העמוד הבא.
שאלות נפוצות
למה משמש package.json?
זה קובץ ה-manifest של פרויקט Node.js. הוא מתעד את השם והגרסה של הפרויקט, באילו חבילות הוא תלוי, אילו סקריפטים אפשר להריץ עם npm run, ומטא-דאטה כמו נקודת הכניסה וסוג המודולים. npm install קורא אותו כדי להחליט מה להוריד.
מה ההבדל בין dependencies לבין devDependencies?
dependencies הן חבילות שהקוד שלכם צריך בזמן ריצה, דברים כמו express או react. devDependencies נחוצות רק בזמן פיתוח או בנייה: כלי הרצת בדיקות, bundlers, linters. כשמישהו מתקין את החבילה שלכם כתלות של החבילה שלו, npm מדלג על ה-devDependencies שלכם.
מה המשמעות של ^ ו-~ בגרסאות ב-package.json?
אלה אופרטורים של טווחי semver. ^1.2.3 מתיר כל גרסת 1.x.x מ-1.2.3 ומעלה (אותה גרסה ראשית). ~1.2.3 קפדני יותר: הוא מתיר 1.2.x מ-1.2.3 ומעלה (אותה גרסה משנית). 1.2.3 לבד נועל את הגרסה המדויקת. package-lock.json מתעד את הגרסאות המדויקות שנבחרו, כך שההתקנות נשארות ניתנות לשחזור.
איך יוצרים קובץ package.json?
הריצו npm init בתיקייה ריקה וענו על השאלות, או הריצו npm init -y כדי לקבל את ברירות המחדל ולקבל קובץ מיד. אפשר גם לכתוב אותו ידנית: זה פשוט JSON. השדות היחידים שבאמת חובה הם name ו-version.