Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «CommonJS проти ES Modules». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**CommonJS** (`require`/`module.exports`) завантажує модулі синхронно й копіює значення під час імпорту; **ES Modules** (`import`/`export`) завантажуються статично, асинхронно й дають живі посилання на експортовані значення. **Ключове:** ESM підтримує tree-shaking і top-level await, бо його імпорти статичні й відомі ще до виконання коду.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## 1. Що таке CommonJS та ES Modules | Модульна система | Де з'явилася | Ключова мета | |---|---|---| | **CommonJS (CJS)** | У Node.js (2009) | Дозволити використовувати модулі в серверному JavaScript | | **ES Modules (ESM)** | У стандарті ECMAScript (ES6, 2015) | Створити нативну модульну систему для JS (браузери + Node.js) | ## 2. Синтаксис ### CommonJS: ```javascript // math.js const PI = 3.14; function add(a, b) { return a + b; } module.exports = { PI, add }; // main.js const math = require('./math'); console.log(math.add(2, 3)); // 5 ``` Використовує: - `require()` - імпорт модулів - `module.exports` / `exports` - експорт модулів ### ES Modules: ```javascript // math.mjs export const PI = 3.14; export function add(a, b) { return a + b; } // main.mjs import { add } from './math.mjs'; console.log(add(2, 3)); // 5 ``` Використовує: - `import` / `export` - ключові слова стандарту ES6 - Підтримується нативно браузером і Node.js (за правильного налаштування) ## 3. Головні відмінності | № | Критерій | CommonJS (CJS) | ES Modules (ESM) | |---|---|---|---| | 1 | **Синтаксис** | `require`, `module.exports` | `import`, `export` | | 2 | **Завантаження модулів** | Динамічне (під час виконання) | Статичне (під час парсингу) | | 3 | **Тип імпорту** | Копія значення (by value) | Жива посилання (by reference) | | 4 | **Асинхронність** | Синхронне завантаження | Асинхронне завантаження | | 5 | **Можливість "top-level await"** | немає | є | | 6 | **Контекст** `this` | `this` вказує на `module.exports` | `this` - `undefined` (строгий режим) | | 7 | **Кешування модулів** | Так (одноразове завантаження) | Так, але з іншим механізмом | | 8 | **Підтримка в Node.js** | За замовчуванням (`.js`) | Потрібно вказати `"type": "module"` або використовувати `.mjs` | | 9 | **Сумісність** | Старі пакети (npm, Express тощо) | Новий стандарт ECMAScript | | 10 | **Використання в браузері** | немає (тільки Node.js) | є (у `<script type="module">`) | ## 4. Статичне vs динамічне завантаження - **CommonJS:** Модуль завантажується **під час виконання** - `require()` можна викликати будь-де: ```javascript if (condition) { const utils = require('./utils'); } ``` - **ES Modules:** Імпорти **статичні** - мають бути **на початку файлу**: ```javascript import utils from './utils.js'; // не можна всередині if ``` Це дозволяє ESM: - робити **tree-shaking** (видаляти невикористовуваний код); - оптимізувати збірку й виконання. ## 5. Живі посилання (Live Bindings) ES Modules підтримують **live bindings** - якщо значення в модулі змінюється, імпорт теж оновлюється. ### ESM: ```javascript // counter.mjs export let count = 0; export function increment() { count++; } // main.mjs import { count, increment } from './counter.mjs'; increment(); console.log(count); // 1 (оновилося) ``` ### CJS: ```javascript // counter.js let count = 0; function increment() { count++; } module.exports = { count, increment }; // main.js const { count, increment } = require('./counter'); increment(); console.log(count); // 0 (копія значення) ``` ## 6. Підтримка в Node.js ### CommonJS - увімкнено за замовчуванням Файли `.js` вважаються CommonJS, якщо не вказано `"type": "module"`. ### ES Modules - потрібно явно увімкнути Два способи: 1. У `package.json`: ```javascript { "type": "module" } ``` → тоді всі `.js` файли вважаються ESM. 2. Або використовувати розширення `.mjs`: ```javascript node main.mjs ``` ## 7. Приклад змішаного коду ### Імпорт CommonJS з ESM: ```javascript // ESM import pkg from './math.cjs'; console.log(pkg.add(2, 3)); ``` ### Імпорт ESM з CommonJS: ```javascript // CJS (async () => { const { add } = await import('./math.mjs'); console.log(add(2, 3)); })(); ``` Зверни увагу: у CJS імпорт ESM **тільки асинхронний** через `import()`. ## 8. Контекст `this` і глобальні змінні | Особливість | CommonJS | ES Modules | |---|---|---| | `this` | Вказує на `module.exports` | `undefined` | | Глобальні об'єкти | `__dirname`, `__filename`, `require`, `module`, `exports` | відсутні (можна імпортувати вручну через `import.meta.url`) | ## 9. Підтримка в npm-пакетах - Старі пакети (`express`, `mongoose`, `chalk@4`) - CommonJS. - Нові (`chalk@5`, `node-fetch`, `axios@next`) - ES Modules. При змішуванні часто виникають помилки: ```javascript Error [ERR_REQUIRE_ESM]: Must use import to load ES Module ``` ## 10. Підсумкова порівняльна таблиця | Характеристика | CommonJS | ES Modules | |---|---|---| | Формат файлів | `.js` | `.mjs` / `.js` при `"type": "module"` | | Імпорт | `require()` | `import` | | Експорт | `module.exports` | `export` | | Завантаження | Синхронне | Асинхронне | | Тип зв'язку | Копія | Жива посилання | | Контекст `this` | `module.exports` | `undefined` | | Браузери | немає | так | | Tree-shaking | немає | так | | Top-level await | немає | так | | Сумісність | Старі пакети | Новий стандарт | ## Коротко: > **CommonJS** - стара, синхронна, специфічна для Node.js система модулів. > **ES Modules** - сучасний, стандартний і крос-платформний формат, що підтримується і Node.js, і браузерами.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.