ES6 модули в JavaScript: import/export — практическое руководство для начинающих

ES6 модули в JavaScript: import/export — практическое руководство для начинающих

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» и закрепить работу с модулями на реальных задачах.

    Источник

    НЕТ КОММЕНТАРИЕВ

    Оставить комментарий