Як працює система модулів в 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 дозволяє створювати модульні, підтримувані та ефективні додатки.