Skip to main content

module resolution

1. Що таке "module resolution"

Module resolution - це процес, за допомогою якого Node.js знаходить фізичний файл (модуль) за іменем, указаним у require() чи import.

Простіше кажучи:

javascript
const express = require('express');

означає:

Node.js має знайти, де саме розташований модуль express - у ядрі, у node_modules, чи за локальним шляхом.

2. Загальна послідовність пошуку

Коли Node.js зустрічає require('щось'), він проходить п'ять етапів:

  1. Перевіряє, чи не є це вбудованим (core) модулем;
  2. Перевіряє, чи не є це шляхом до файлу (./, ../, /);
  3. Інакше вважає, що це модуль з node_modules;
  4. Шукає його в найближчих node_modules вгору по дереву директорій;
  5. Якщо не знайдено - викидає помилку MODULE_NOT_FOUND.

3. Типи модулів, які Node.js вміє розв'язувати

ТипПрикладОпис
Core (вбудовані)fs, path, os, httpВбудовані в Node.js - не потребують встановлення
Локальні файли./utils.js, ../config.jsonТвої власні файли
Пакети (npm)express, chalk, mongooseШукаються в node_modules
JSON / бінарніconfig.json, addon.nodeАвтоматично парсяться чи завантажуються як бінарні

4. Алгоритм module resolution (для CommonJS)

Приклад:

javascript
const utils = require('./utils');

Node.js робить таке:

  1. Перевіряє, чи є './utils' шляхом:
  • чи починається з ./, ../ чи / - так.
  1. Перетворює шлях в абсолютний:
javascript
/Users/tim/project/utils
  1. Пробує наступні варіанти (по порядку):
javascript
utils.js utils.json utils.node utils/index.js utils/index.json utils/index.node
  1. Якщо нічого не знайдено → помилка:
javascript
Error: Cannot find module './utils'

5. Алгоритм для пакетів з node_modules

Приклад:

javascript
const express = require('express');

Node.js:

  1. Шукає вбудований модуль express → немає.
  2. Шукає node_modules/express у поточній папці.
  3. Якщо не знайдено → піднімається вище по дереву:
javascript
/Users/tim/project/node_modules/express /Users/tim/node_modules/express /Users/node_modules/express /node_modules/express
  1. Знайшов → читає файл express/package.json.
  2. У ньому шукає поле "main":
javascript
{ "name": "express", "main": "index.js" }
  1. Завантажує /node_modules/express/index.js.

6. Приклад візуально

javascript
project/ ├── app.js ├── utils/ │ └── index.js └── node_modules/ └── lodash/ ├── package.json └── lodash.js
javascript
require('./utils'); // → ./utils/index.js require('lodash'); // → ./node_modules/lodash/lodash.js require('fs'); // → вбудований модуль Node.js

7. Як Node.js обирає між .js, .json і .node

Node пробує розширення в такому порядку:

  1. .js - звичайний JavaScript-файл;
  2. .json - автоматично парситься в об'єкт;
  3. .node - бінарний нативний модуль (C++).

Приклад:

javascript
require('./config'); // спробує config.js → config.json → config.node

8. Module resolution для ES Modules (ESM)

Для ESM (import/export) алгоритм інший - суворіший:

  • Потрібно вказувати точне розширення (.js, .mjs, .json);
  • Папки з index.js не шукаються автоматично;
  • __dirname та __filename відсутні;
  • "exports" у package.json визначає доступні шляхи.

Приклад:

javascript
import utils from './utils/index.js'; // обов'язково з розширенням

9. Як package.json впливає на module resolution

Node.js дивиться на поля:

ПолеПризначення
"main"Головна точка входу для CommonJS
"exports"Сучасна альтернатива для ESM / CJS
"type"Визначає тип модулів (commonjs чи module)

Приклад:

javascript
{ "name": "my-lib", "main": "./dist/index.cjs", "exports": { "import": "./dist/index.mjs", "require": "./dist/index.cjs" }, "type": "module" }

Node буде використовувати "exports" замість "main", якщо воно вказане - це сучасний спосіб контролювати, які файли можна імпортувати ззовні.

10. Кешування під час module resolution

Коли Node.js розв'язав модуль і завантажив його, результат зберігається в require.cache:

javascript
console.log(require.cache);

Повторний require() не виконує файл заново - просто повертає його exports із кешу. Це прискорює завантаження й запобігає рекурсивним циклам (circular dependencies).

11. Інструменти для налагодження resolution

Якщо хочеш подивитися, звідки саме підхоплюється модуль:

javascript
node -p "require.resolve('express')"

Приклад виводу:

javascript
/Users/tim/project/node_modules/express/index.js

Чи для локального файлу:

javascript
node -p "require.resolve('./utils')"

Одним реченням

Module resolution - це механізм, за допомогою якого Node.js визначає, де фізично знаходиться модуль, указаний у require() чи import, проходячи через вбудовані, локальні й node_modules, поки не знайде потрібний файл.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.