Модули: ES Modules в браузере
ES Modules (ESM) — нативный стандарт модульной системы JavaScript, поддерживаемый современными браузерами напрямую без сборщика через import/export.
Зачем нужно
До ESM в браузере не было официальной модульной системы: разработчики использовали глобальные переменные или конкатенацию файлов. Node.js сделал CommonJS (require/module.exports) стандартом, затем ES2015 принёс нативный ESM. Понимание ESM объясняет как работают сборщики (Webpack, Vite), почему Vite так быстро стартует в dev-режиме и как браузер самостоятельно загружает зависимости.
Где используется
- Vite dev-server — сервирует ESM-модули напрямую без бандлинга
- Браузер с
<script type="module">— нативная загрузка - Node.js с расширением
.mjsили"type": "module"в package.json - CDN-импорты для экспериментов:
import { createApp } from 'https://esm.sh/vue'
Синтаксис ESM
// math.js — экспорт
export function add(a, b) { return a + b; }
export function multiply(a, b) { return a * b; }
// default export — один на модуль
export default function greet(name) {
return `Привет, ${name}!`;
}
// Переменные и константы
export const PI = 3.14159;
export class Calculator { /* ... */ }
// app.js — импорт
import greet, { add, multiply, PI } from './math.js';
// Переименование при импорте
import { add as sum } from './math.js';
// Импорт всего namespace
import * as MathUtils from './math.js';
MathUtils.add(1, 2);
// Динамический импорт — возвращает промис
const { add } = await import('./math.js');
// Side-effect only импорт (полифиллы, стили)
import './polyfills.js';
ESM в браузере без сборщика
<!DOCTYPE html>
<html>
<head>
<!-- type="module" — включает ESM -->
<!-- defer по умолчанию, всегда выполняется после парсинга HTML -->
<script type="module" src="./app.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
// app.js
// Браузер загружает и выполняет граф зависимостей автоматически
import { render } from './renderer.js';
import { createRouter } from './router.js';
// Относительные пути обязательны (./ или ../)
// Голые импорты ('react') не работают без Import Map
import { add } from './math.js'; // OK
import { add } from 'math'; // Ошибка без Import Map
Import Maps — голые импорты в браузере
<!-- Современные браузеры поддерживают Import Maps (2023+) -->
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@18",
"react-dom/client": "https://esm.sh/react-dom@18/client"
}
}
</script>
<script type="module">
import React from 'react'; // теперь работает
import { createRoot } from 'react-dom/client';
</script>
ESM vs CommonJS
// CommonJS (Node.js, require)
const { add } = require('./math'); // синхронный
module.exports = { add };
// ESM — статический анализ → tree-shaking возможен
import { add } from './math.js'; // статический
export { add };
// CJS нельзя статически проанализировать:
const moduleName = condition ? 'a' : 'b';
const mod = require(moduleName); // динамический путь
Частые ошибки
- Забывают расширение
.js— в браузерном ESM путь должен быть точным:./math.js, не./math. - CORS ошибка при открытии через
file://— ESM требует HTTP-сервера; используйтеnpx serveили Live Server. - Смешивают CJS и ESM —
requireне работает в ESM-контексте браузера; используйте толькоimport/export.
Связанные темы
- _MOC SPA
- Bundle vs Unbundle -- разница
- Code Splitting -- разделение кода
- HMR -- Hot Module Replacement