מודולים ו-npm

מודולים הם הדרך לארגן ולשתף קוד ב-Node.js. הם מאפשרים לפצל את הקוד לקבצים קטנים וניתנים לשימוש חוזר.


מהו מודול?

מודול הוא פשוט קובץ JavaScript שמייצא פונקציונליות.

┌─────────────────────────────────────────────────────┐
│                    app.js (ראשי)                     │
├─────────────────────────────────────────────────────┤
│  require('./utils')    require('http')              │
│         │                    │                      │
│         ▼                    ▼                      │
│  ┌─────────────┐     ┌─────────────┐               │
│  │  utils.js   │     │  http       │               │
│  │  (שלנו)     │     │  (מובנה)    │               │
│  └─────────────┘     └─────────────┘               │
└─────────────────────────────────────────────────────┘

CommonJS (הדרך המסורתית)

ייצוא (Export)

// utils.js

// ייצוא פונקציה בודדת
function add(a, b) {
    return a + b;
}

function subtract(a, b) {
    return a - b;
}

// אופציה 1: ייצוא נפרד
module.exports.add = add;
module.exports.subtract = subtract;

// אופציה 2: ייצוא כאובייקט (נפוץ יותר)
module.exports = {
    add,
    subtract
};

// אופציה 3: קיצור עם exports
exports.multiply = (a, b) => a * b;

ייבוא (Import)

// app.js

// ייבוא כל המודול
const utils = require('./utils');
console.log(utils.add(2, 3));  // 5

// ייבוא עם destructuring (מומלץ)
const { add, subtract } = require('./utils');
console.log(add(2, 3));  // 5
console.log(subtract(5, 2));  // 3

// ייבוא מודול מובנה
const fs = require('fs');
const path = require('path');

// ייבוא חבילה מ-node_modules
const express = require('express');

ייצוא ערך בודד

// logger.js
class Logger {
    log(message) {
        console.log(`[LOG] ${message}`);
    }
    error(message) {
        console.error(`[ERROR] ${message}`);
    }
}

module.exports = Logger;

// app.js
const Logger = require('./logger');
const logger = new Logger();
logger.log('שלום!');

ES Modules (הדרך המודרנית)

ES Modules הם התקן החדש יותר, משמשים גם בדפדפנים וגם ב-Node.js.

הפעלת ES Modules

שתי דרכים: 1. שימוש בסיומת .mjs 2. הוספת "type": "module" ל-package.json

ייצוא (Export)

// utils.mjs

// Named exports
export function add(a, b) {
    return a + b;
}

export function subtract(a, b) {
    return a - b;
}

// או בסוף הקובץ
function multiply(a, b) {
    return a * b;
}
export { multiply };

// Default export (אחד לקובץ)
export default class Calculator {
    // ...
}

ייבוא (Import)

// app.mjs

// Named imports
import { add, subtract } from './utils.mjs';
console.log(add(2, 3));

// ייבוא עם שינוי שם
import { add as addition } from './utils.mjs';

// ייבוא default
import Calculator from './utils.mjs';

// ייבוא הכל
import * as utils from './utils.mjs';
console.log(utils.add(2, 3));

// ייבוא מודולים מובנים
import fs from 'fs';
import { readFile } from 'fs/promises';

השוואה: CommonJS vs ES Modules

CommonJS ES Modules
require() import
module.exports export
סינכרוני אסינכרוני
דינמי (ניתן לעשות require בתנאי) סטטי (חייב להיות בראש הקובץ)
ברירת מחדל ב-Node.js תקן JavaScript מודרני
סיומת .js סיומת .mjs או "type": "module"
// CommonJS - דינמי (מותר)
if (condition) {
    const module = require('./module');
}

// ES Modules - סטטי (אסור בראש הקובץ)
// import { something } from './module';  // חייב להיות בראש!

// ES Modules - dynamic import (מותר)
if (condition) {
    const module = await import('./module.mjs');
}

מודולים מובנים (Built-in)

Node.js מגיע עם מודולים מובנים שימושיים:

fs - מערכת קבצים

const fs = require('fs');

// קריאת קובץ (סינכרוני)
const data = fs.readFileSync('file.txt', 'utf8');

// קריאת קובץ (אסינכרוני)
fs.readFile('file.txt', 'utf8', (err, data) => {
    if (err) throw err;
    console.log(data);
});

path - נתיבים

const path = require('path');

path.join('/users', 'israel', 'docs');  // /users/israel/docs
path.basename('/users/file.txt');        // file.txt
path.extname('file.txt');                // .txt
path.dirname('/users/file.txt');         // /users
path.resolve('file.txt');                // נתיב מוחלט

http - שרת HTTP

const http = require('http');

const server = http.createServer((req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('שלום עולם!');
});

server.listen(3000);

os - מערכת הפעלה

const os = require('os');

console.log(os.platform());    // win32, linux, darwin
console.log(os.cpus().length); // מספר מעבדים
console.log(os.totalmem());    // זיכרון כולל
console.log(os.homedir());     // תיקיית הבית

crypto - הצפנה

const crypto = require('crypto');

// Hash
const hash = crypto.createHash('sha256')
    .update('סיסמה')
    .digest('hex');

// UUID
const uuid = crypto.randomUUID();

url - ניתוח URLs

const url = require('url');

const myUrl = new URL('https://example.com:8080/path?name=ישראל');
console.log(myUrl.hostname);  // example.com
console.log(myUrl.port);      // 8080
console.log(myUrl.pathname);  // /path
console.log(myUrl.searchParams.get('name'));  // ישראל

תיעוד מפורט למודולים מובנים

לכל מודול יש תיעוד מפורט הכולל תחביר, פרמטרים וערכים מוחזרים:

מודול קישור
fs - קבצים ותיקיות התיעוד של fs
path - נתיבים התיעוד של path
os - מערכת הפעלה התיעוד של os
http - שרת HTTP התיעוד של http
events - EventEmitter התיעוד של events

npm - מנהל החבילות

מהו npm?

npm (Node Package Manager) הוא: 1. מאגר - אתר עם מיליוני חבילות 2. כלי - תוכנה שמנהלת חבילות

פקודות בסיסיות

# Create package.json (תחילת פרויקט)
npm init
npm init -y  # עם ערכי ברירת מחדל

# התקנת חבילה
npm install express    # או npm i express
npm install mongoose lodash  # מספר חבילות

# התקנת חבילת פיתוח בלבד
npm install --save-dev jest  # או npm i -D jest

# התקנה גלובלית
npm install -g nodemon

# הסרת חבילה
npm uninstall express

# התקנת כל התלויות מ-package.json
npm install

# הרצת סקריפטים
npm run start
npm run dev
npm test  # קיצור ל-npm run test

קובץ package.json

{
  "name": "my-project",
  "version": "1.0.0",
  "description": "פרויקט לדוגמה",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "test": "jest"
  },
  "keywords": ["example", "nodejs"],
  "author": "ישראל ישראלי",
  "license": "MIT",
  "dependencies": {
    "express": "^4.18.2",
    "mongoose": "^7.0.0"
  },
  "devDependencies": {
    "jest": "^29.0.0",
    "nodemon": "^3.0.0"
  }
}

הסבר גרסאות

"express": "^4.18.2"
            │ │  │
            │ │  └─ Patch (תיקוני באגים)
            │ └──── Minor (תכונות חדשות תואמות)
            └────── Major (שינויים שוברים)

^4.18.2 - מאפשר עדכון Minor ו-Patch (4.19.0, 4.18.3)
~4.18.2 - מאפשר עדכון Patch בלבד (4.18.3)
4.18.2  - גרסה מדויקת בלבד

node_modules ו-.gitignore

מה זה node_modules?

תיקייה שמכילה את כל החבילות שהתקנתם ואת התלויות שלהן.

⚠️ אף פעם אל תעלו את node_modules ל-Git!

# .gitignore
node_modules/
.env

למה?

  • התיקייה יכולה להכיל אלפי קבצים
  • ניתן לשחזר אותה עם npm install

package-lock.json

קובץ שנוצר אוטומטית ושומר את הגרסאות המדויקות של כל התלויות.

✅ כן תעלו ל-Git! זה מבטיח שכל המפתחים משתמשים באותן גרסאות.


חבילות פופולריות

חבילה שימוש
express framework לשרתים
mongoose עבודה עם MongoDB
axios בקשות HTTP
lodash פונקציות שימושיות
dotenv משתני סביבה מ-.env
bcrypt הצפנת סיסמאות
jsonwebtoken אימות JWT
nodemon הפעלה מחדש אוטומטית
jest בדיקות
eslint בדיקת קוד

סיכום

נושא CommonJS ES Modules
ייבוא require() import
ייצוא module.exports export
ברירת מחדל ✅ ב-Node.js דורש הגדרה

← חזרה לתחביר | → המשך לתכנות אסינכרוני

בדקו את עצמכם

נסו לענות לבד לפני שאתם פותחים את התשובה.

  1. מה צריך ב-package.json כדי לכתוב import ו-export בקובצי .js?

    1. שום דבר
    2. "type": "module"
    3. "esm": "on"
    4. "module": true
    הצגת התשובה

    תשובה ב. בלי זה Node.js מתייחס לקובצי .js כ-CommonJS (require).

  2. למה node_modules לא עולה ל-Git?

    1. הוא ענק, ואפשר ליצור אותו מחדש מ-package.json עם npm install
    2. הוא נמחק אוטומטית
    3. הוא סודי
    4. Git לא תומך בתיקיות
    הצגת התשובה

    תשובה א. מה שכן עולה: package.json ו-package-lock.json.

  3. מה תפקיד package-lock.json?

    1. להחליף את package.json
    2. לתעד את הגרסאות המדויקות שהותקנו, כדי שכל התקנה תהיה זהה
    3. לנעול את הפרויקט
    4. להצפין חבילות
    הצגת התשובה

    תשובה ב. npm ci מתקין בדיוק לפיו, ולכן הוא חיוני בשרת וב-CI.