Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «ESM проти CommonJS». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**CommonJS** - модульна система Node.js, де модулі завантажуються синхронно під час виконання (runtime), а імпорти є копією значень. **ES Modules (ESM)** - стандартизована система ECMAScript, де модулі аналізуються ще на етапі компіляції (parse-time), завантажуються асинхронно, а імпорти є «живими» посиланнями (live bindings). **Ключове:** CommonJS - динамічна, синхронна, специфічна для Node.js система, де імпорти виконуються під час запуску, а ES Modules - статична, асинхронна, стандартизована система, де залежності відомі заздалегідь і імпорт створює живі посилання.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## 1. Коротко: головна ідея | Система | Основна концепція | |---|---| | **CommonJS (CJS)** | Модулі завантажуються **під час виконання** (runtime), синхронно, порядково. | | **ES Modules (ESM)** | Модулі аналізуються **на етапі компіляції** (parse-time), завантажуються **асинхронно**, із суворими залежностями та «живими» імпортами. | ## 2. Філософія систем ### CommonJS Створювався **для Node.js** (2009 рік), щоб виконувати JS на сервері. - Усе синхронно (адже файли - на локальному диску); - Кожен файл - ізольований модуль; - Код виконується згори вниз під час першого `require()`; - Імпорти - це **копія значень**, а не «живі посилання». Приклад: ```javascript // math.js module.exports = { x: 1 }; // app.js const math = require('./math'); console.log(math.x); // 1 math.x = 2; // зміна лише локальної копії ``` ### ES Modules Створювалися **для мови JavaScript** (ES6, 2015 рік), щоб один стандарт працював і в браузерах, і в Node.js. - Завантаження **асинхронне**, декларативне; - Імпорти **статичні** - відомі ще до виконання коду; - Можна оптимізувати, робити *tree-shaking*; - Імпорти - це **live bindings**, тобто «живі» посилання, а не копії. Приклад: ```javascript // counter.js export let count = 0; export function inc() { count++; } // app.js import { count, inc } from './counter.js'; inc(); console.log(count); // 1 (значення оновилося) ``` ## 3. Концептуальні відмінності | Концепція | CommonJS | ES Modules | |---|---|---| | **Час завантаження** | Під час виконання (runtime) | До виконання (parse-time) | | **Імпорти** | Динамічні (`require()`) | Статичні (`import`) | | **Тип зв'язку** | Значення копіюються | Живі посилання (live bindings) | | **Порядок виконання** | Згори вниз | Визначається залежностями | | **Асинхронність** | Синхронно | Асинхронно | | **Оптимізація** | Неможлива (runtime) | Можливий tree-shaking | | **Контекст** | `this` = `module.exports` | `this` = `undefined` | | **Кешування** | Після першого виклику | Є, але із «живими» значеннями | | **Екосистема** | Node.js, старі пакети | Сучасний JS, браузери, Node 13+ | | **Архітектура** | Імперативна | Декларативна | | **Сумісність** | Лише сервер | Універсальна (сервер + клієнт) | ## 4. Різниця в моменті завантаження і компіляції ### CommonJS: - Виконується рядок `require()` → читається файл → виконується код. - Тому шлях може бути змінною: ```javascript const lib = require(condition ? './a' : './b'); ``` Працює, тому що це звичайна функція. ### ES Modules: - Імпорти повинні бути **у верхній частині файлу** і **не можуть бути динамічними**: ```javascript import x from './a'; // коректно if (cond) import x from './b'; // помилка ``` - Node.js і браузер знають заздалегідь, які залежності потрібні, і можуть завантажувати їх **паралельно** до виконання коду. ## 5. Різниця в структурі модуля Node.js «обгортає» CommonJS-модуль у внутрішню функцію: ```javascript (function (exports, require, module, __filename, __dirname) { // твій код }); ``` Тому є: - `require` - `module.exports` - `__dirname` - `__filename` У ESM цього немає: - замість `__dirname` → `import.meta.url` - `require` недоступний ## 6. Поведінка під час кешування У CommonJS модуль виконується один раз і **кешується**: ```javascript const a = require('./a'); const b = require('./a'); console.log(a === b); // true ``` У ESM теж є кеш, але імпорти залишаються **живими** (якщо змінні експортовані як let/const): ```javascript import { counter } from './a.js'; ``` Якщо модуль оновлює значення, усі імпорти бачать оновлення. ## 7. Tree-shaking та оптимізація Tree-shaking - це видалення невикористаного коду (у Webpack, Rollup, Vite тощо). - **CJS:** неможливо, тому що імпорти динамічні; - **ESM:** можливо, тому що залежності статичні. Приклад: ```javascript import { used } from './utils.js'; // бандлер знає, що потрібен лише used ``` ## 8. Сумісність | Сценарій | CommonJS | ES Modules | |---|---|---| | Використовувати старі пакети | Так | Іноді потрібен `createRequire()` | | SSR / сервер | Відмінно | Відмінно (Node 13+) | | Браузери | Ні | Так | | Tree-shaking | Ні | Так | | Top-level await | Ні | Так | ## 9. «Живі» проти «мертвих» імпортів (приклад) ### CommonJS: ```javascript // counter.js let count = 0; module.exports = { count, inc() { count++; } }; // app.js const c = require('./counter'); c.inc(); console.log(c.count); // 0 (копія) ``` ### ES Modules: ```javascript // counter.mjs export let count = 0; export function inc() { count++; } // app.mjs import { count, inc } from './counter.mjs'; inc(); console.log(count); // 1 (живе посилання) ``` ## 10. Концептуально: ключові відмінності | Параметр | CommonJS | ESM | |---|---|---| | Основа | Node.js (сервер) | Стандарт ECMAScript | | Модель виконання | Виконує одразу (runtime) | Спочатку аналізує залежності | | Імпорти | Можна в будь-якому місці | Лише на верхньому рівні | | Доступ до оточення | `require`, `module`, `exports`, `__dirname` | `import.meta.url`, `import/export` | | Сумісність | Багато старих бібліотек | Сучасні бандлери та браузери | | Продуктивність | Швидше при локальних require | Ефективніше у великих проєктах | ## Одним реченням: > **CommonJS** - динамічна, синхронна, специфічна для Node.js модульна система, де імпорти виконуються під час запуску. > **ES Modules** - статична, асинхронна, стандартизована система, де залежності відомі заздалегідь, а імпорт створює живі посилання.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.