ES6 модули в JavaScript: import/export — практическое руководство для начинающих
ES6 модули — стандартный способ организовывать код в JavaScript. Они делают проекты понятнее, ускоряют загрузку в браузере и упрощают тестирование. В этой статье разберём import и export на практических примерах, покажем настройки для браузера и Node.js, а также типичные ошибки, которые встречаются у новичков.
Что такое ES‑модуль
ES‑модуль — это файл, в котором используются ключевые слова export и import. Всё, что не экспортировано, остаётся приватным внутри файла. Модули выполняются один раз, а затем кэшируются средой (браузером или Node.js).
Базовый пример: export и import
Создадим модуль с функциями и подключим его из другого файла.
// src/math.js
export const sum = (a, b) => a + b;
export const mul = (a, b) => a * b;
export default function avg(...nums) {
if (nums.length === 0) return 0;
return nums.reduce((a, n) => a + n, 0) / nums.length;
}
// src/index.js
import avg, { sum, mul } from './math.js';
console.log(sum(2, 3)); // 5
console.log(mul(2, 3)); // 6
console.log(avg(10, 20, 30)); // 20
Здесь мы используем два вида экспорта:
- Именованный экспорт — можно импортировать несколько сущностей в фигурных скобках: { sum, mul }
- Экспорт по умолчанию (default) — импортируется без фигурных скобок под любым именем: avg
Именованный vs default: частые ошибки
- Нельзя импортировать default как именованный: import { avg } from './math.js' — будет undefined.
- В одном модуле может быть только один default‑экспорт, а именованных — сколько угодно.
- Переименовывайте при импорте, если конфликтуют имена: import { sum as add } from './math.js'.
Переэкспорт и «индексные» модули
Часто удобно собирать публичный API пакета в одном месте.
// src/utils/string.js
export const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
export const kebab = (s) => s.replaceAll(/\s+/g, '-').toLowerCase();
// src/utils/index.js (агрегатор)
export { sum, mul } from '../math.js';
export * from './string.js'; // реэкспорт всех именованных экспортов
// src/app.js
import { sum, capitalize, kebab } from './utils/index.js';
console.log(sum(1, 2));
console.log(capitalize('hello'));
console.log(kebab('Hello World'));
Динамический импорт: import()
Когда модуль нужен не сразу, используйте динамическую загрузку — это улучшает производительность.
// src/on-demand.js
const btn = document.querySelector('#calc');
btn.addEventListener('click', async () => {
const { sum } = await import('./math.js');
console.log('Результат:', sum(40, 2));
});
Динамический импорт возвращает промис и работает и в браузере, и в Node.js.
Top‑level await в модулях
В модулях можно использовать await на верхнем уровне — без async‑функции.
// src/config.js
export const config = await fetch('/config.json').then(r => r.json());
// src/main.js
import { config } from './config.js';
console.log('Конфиг загружен:', config);
Импортирующий модуль подождёт, пока config.js завершит асинхронную инициализацию.
Модули в браузере: подключение через script type="module"
<!-- index.html -->
<script type="module" src="./src/main.js"></script>
<!-- Модули выполняются в строгом режиме, поддерживают импорт по ссылкам и TLA -->
- Всегда указывайте расширение в путях: ./math.js (без сборщика браузер не найдёт файл).
- Пути должны быть абсолютными или начинаться с ./ или ../ — «голые» импорты вроде import 'lodash' нужны только со сборщиком или import maps.
- Запускайте через локальный сервер: из file:// импорты часто блокируются CORS/политиками безопасности.
Модули в Node.js: .mjs и package.json
Node поддерживает ESM двумя способами:
- Имя файла заканчивается на .mjs
- В package.json указан "type": "module"
// package.json
{
"name": "esm-demo",
"type": "module",
"version": "1.0.0"
}
// index.js (ESM)
import { readFile } from 'node:fs/promises';
const txt = await readFile(new URL('./README.md', import.meta.url), 'utf8');
console.log(txt.slice(0, 50));
В ESM для корректных путей используйте import.meta.url или стандартные URL‑конструкторы. Помните, что в ESM по умолчанию нет __dirname и __filename.
Смешение CommonJS и ESM
- Импортировать CJS из ESM можно динамически: const mod = await import('cjs-package') — Node преобразует экспорт автоматически.
- Импортировать ESM из CJS — через import() или createRequire; лучше мигрировать на ESM во всём проекте.
Мини‑кейс: модульная утилита для форматирования
// src/format/number.js
export const money = (n, currency = '₽') =>
new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB' })
.format(n).replace('RUB', currency);
// src/format/date.js
export const shortDate = (d = new Date()) =>
new Intl.DateTimeFormat('ru-RU').format(d);
// src/format/index.js
export * from './number.js';
export * from './date.js';
// src/demo.js
import { money, shortDate } from './format/index.js';
console.log(money(1999));
console.log(shortDate());
Такой подход облегчает реэкспорт, тестирование и «тряску дерева» (tree‑shaking) в сборщиках.
Частые ошибки и советы
- Забыли расширение в браузере: import './utils' — исправьте на './utils.js'.
- Смешали default и именованные: import { default as x } — почти всегда сигнал неверного дизайна модуля; используйте либо default, либо именованные API последовательно.
- Круговые зависимости: A импортирует B, а B — A. Вынесите общий код в третий модуль C или пересмотрите архитектуру.
- Побочные эффекты: выполнение кода на верхнем уровне модуля запускается один раз. Держите инициализацию предсказуемой, экспортируйте функции и константы, избегайте «магии».
- «Голые» импорты в браузере: используйте import maps или CDN с абсолютным URL, либо сборщик (Vite/Webpack/Rollup).
Итоги
ES6 модули — фундамент современного JavaScript. Освоив именованные и default‑экспорты, динамический импорт и базовые настройки для браузера и Node.js, вы получите предсказуемую архитектуру и выигрыш в производительности. Для системного прокачивания навыков, практики и проектов рекомендую пройти практический курс «JavaScript с Нуля до Гуру 2.0» и закрепить работу с модулями на реальных задачах.
-
Создано 02.02.2026 17:05:27
-
Михаил Русаков

Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.