Середнійmodulescommonjses-modulesrequireexports

Як працює система модулів в Node.js?

Огляд CommonJS, ES Modules та механізму require() в Node.js

Як працює система модулів в Node.js?

Node.js підтримує дві системи модулів: CommonJS (за замовчуванням) та ES Modules. Розуміння обох систем важливе для ефективної розробки.

CommonJS Модулі

Експорт модулів

// math.js
function add(a, b) {
  return a + b;
}

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

const PI = 3.14159;

// Експорт окремих функцій
module.exports.add = add;
module.exports.subtract = subtract;
module.exports.PI = PI;

// Або скорочений синтаксис
exports.multiply = (a, b) => a * b;

// Експорт всього об'єкта
module.exports = {
  add,
  subtract,
  PI,
  multiply: (a, b) => a * b
};

Імпорт модулів

// app.js

// Повний імпорт
const math = require('./math');
console.log(math.add(2, 3)); // 5

// Деструктуризація
const { add, subtract, PI } = require('./math');
console.log(add(2, 3)); // 5

// Вбудовані модулі
const fs = require('fs');
const path = require('path');
const http = require('http');

// NPM пакети
const express = require('express');
const lodash = require('lodash');

ES Modules (ESM)

Активація ES Modules

// package.json
{
  "type": "module"
}

Або використовуйте розширення .mjs:

// math.mjs
export function add(a, b) {
  return a + b;
}

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

export const PI = 3.14159;

// Default export
export default class Calculator {
  add(a, b) { return a + b; }
  subtract(a, b) { return a - b; }
}

Імпорт ES Modules

// app.mjs

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

// Default import
import Calculator from './math.mjs';
const calc = new Calculator();

// Комбінований імпорт
import Calculator, { add, PI } from './math.mjs';

// Імпорт всього
import * as math from './math.mjs';
console.log(math.add(2, 3)); // 5

// Динамічний імпорт
const math = await import('./math.mjs');

Механізм require()

Алгоритм пошуку модулів

// Пошук модуля 'express'
require('express');

// 1. Перевірка вбудованих модулів
// 2. Якщо починається з './' або '../' - відносний шлях
// 3. Пошук в node_modules:
//    - ./node_modules/express
//    - ../node_modules/express
//    - ../../node_modules/express
//    - ... до кореня файлової системи

Кешування модулів

// counter.js
let count = 0;

module.exports = {
  increment() { return ++count; },
  getCount() { return count; }
};

// app.js
const counter1 = require('./counter');
const counter2 = require('./counter');

console.log(counter1.increment()); // 1
console.log(counter2.getCount());  // 1 (той самий екземпляр!)

// Очищення кешу
delete require.cache[require.resolve('./counter')];
const counter3 = require('./counter');
console.log(counter3.getCount());  // 0 (новий екземпляр)

Міксування CommonJS та ES Modules

Імпорт CommonJS в ES Modules

// commonjs-module.js
module.exports = {
  name: 'CommonJS Module',
  version: '1.0.0'
};

// es-module.mjs
import module from './commonjs-module.js';
console.log(module.name); // 'CommonJS Module'

// Або динамічний імпорт
const module = await import('./commonjs-module.js');

Імпорт ES Modules в CommonJS

// es-module.mjs
export const name = 'ES Module';
export default { version: '1.0.0' };

// commonjs-module.js
(async () => {
  const { name, default: module } = await import('./es-module.mjs');
  console.log(name); // 'ES Module'
  console.log(module.version); // '1.0.0'
})();

Структура package.json

{
  "name": "my-package",
  "version": "1.0.0",
  "type": "module",
  "main": "index.js",
  "exports": {
    ".": {
      "import": "./index.mjs",
      "require": "./index.cjs"
    },
    "./utils": {
      "import": "./utils/index.mjs",
      "require": "./utils/index.cjs"
    }
  },
  "files": [
    "index.js",
    "utils/"
  ]
}

Найкращі практики

1. Консистентність

// ✅ Добре - консистентне використання
const fs = require('fs').promises;
const path = require('path');
const express = require('express');

// ❌ Погано - змішування стилів
const fs = require('fs');
import express from 'express';

2. Явний експорт

// ✅ Добре - явний експорт
module.exports = {
  add,
  subtract,
  PI: 3.14159
};

// ❌ Погано - неявний експорт
exports.add = add;
exports.subtract = subtract;
module.exports.PI = 3.14159; // змішування

3. Уникання циклічних залежностей

// a.js
const b = require('./b');
module.exports = { name: 'A', b };

// b.js  
const a = require('./a'); // Циклічна залежність!
module.exports = { name: 'B', a };

Розуміння системи модулів Node.js дозволяє створювати модульні, підтримувані та ефективні додатки.