ES-модули в JavaScript: import и export
Содержание
О проверке кода. Примеры не запускались — в отличие от материалов по Node.js с фактическим выводом. Говорим прямо, а не ставим бейдж «проверено».
Как только проект перерастает один файл, нужен способ разбить код на части. ES-модули — стандартный механизм JavaScript из ECMAScript 6, работающий и в браузере, и в Node. Разберём import/export без путаницы.
Именованный экспорт
Файл отдаёт наружу несколько значений по именам:
// math.js
export const PI = 3.14159;
export function square(x) { return x * x; }
export function cube(x) { return x ** 3; }
// main.js — импорт по именам в фигурных скобках
import { square, PI } from './math.js';
square(5); // 25
PI; // 3.14159
Именованный экспорт отдаёт несколько значений, каждое под своим именем. При импорте перечисляют нужные в фигурных скобках — с теми же именами (можно взять не все). Это основной способ, когда файл предоставляет набор утилит.
Переименование при импорте — через as:
import { square as sq } from './math.js'; // локально называем sq
Дефолтный экспорт
Файл отдаёт одно главное значение:
// User.js
export default class User {
constructor(name) { this.name = name; }
}
// main.js — без скобок, имя любое
import User from './User.js'; // можно назвать как угодно
import Whatever from './User.js'; // тоже сработает
Дефолтный экспорт — одно главное значение файла, и при импорте ему дают любое имя без фигурных скобок. Используют, когда файл представляет одну сущность: класс, компонент, главную функцию. В файле может быть только один default.
Именованный export
Несколько значений
export const x,export function- Импорт в скобках:
import { x } - Имена фиксированы (или
as) - Для наборов утилит
export default
Одно главное значение
export default class- Импорт без скобок:
import X - Имя произвольное
- Один на файл, для одной сущности
Их можно сочетать в одном файле: export default для главного плюс именованные для дополнительного.
import против require
Это частый источник путаницы: два синтаксиса для одного дела.
// CommonJS — старый формат Node.js
const math = require('./math');
module.exports = { square };
// ES-модули — стандарт языка
import { square } from './math.js';
export { square };
import/export — стандарт ES-модулей, работает в браузере и современном Node. require/module.exports — CommonJS, исторический формат Node. Ключевые отличия:
importстатический — анализируется до запуска, что позволяет сборщикам удалять неиспользуемый код (tree-shaking);requireдинамический — выполняется в момент вызова, можно вызвать по условию;- у ESM импорты поднимаются и разбираются раньше остального кода.
Новый код пишут на ES-модулях. CommonJS остаётся в старых Node-проектах — подробное сравнение отдельно.
Как включить в Node.js и браузере
// package.json — весь проект как ES-модули
{ "type": "module" }
<!-- браузер — атрибут type="module" -->
<script type="module" src="main.js"></script>
По умолчанию Node трактует .js как CommonJS. Чтобы заработали import/export, добавляют "type": "module" в package.json или дают файлам расширение .mjs. В браузере обычный <script> не понимает import — нужен type="module" (он же включает отложенную загрузку и строгий режим). Забыть это — самая частая ошибка с ошибкой Cannot use import statement outside a module.
Динамический импорт
Обычный import статичен — он в начале файла и грузится всегда. Иногда модуль нужен по условию:
button.addEventListener('click', async () => {
// тяжёлый модуль грузится, только когда реально нужен
const { generateReport } = await import('./report.js');
generateReport();
});
import() — функция, загружающая модуль во время выполнения, возвращает промис. В отличие от статического импорта, её вызывают по условию или по требованию: подгрузить редко используемый модуль только при действии пользователя. Это основа «ленивой загрузки» (code splitting) — страница грузит меньше кода сразу, остальное подтягивает по мере надобности.
Типичные ошибки
- забыть расширение — в браузере и Node ESM путь пишут полностью:
'./math.js', не'./math'; - забыть
"type": "module"— Node ругается наimport; - перепутать скобки — дефолтный импорт без
{ }, именованный с{ }; - смешать форматы —
requireиimportв одном файле обычно не уживаются.
Смежные темы: ESM против CommonJS — подробное сравнение; ECMAScript 6 — откуда модули; промисы — динамический import. Полный список — в уроках JavaScript.