Модули, импорты, экспорты
Автор конспекта: Арина Василевская
Полезные ссылки:
Начало работы
Для начала создадим папку с названием, например lesson-05 и в ней файлы index.html, main.js,
player.js, analytics.js
- index.html
- main.js
- player.js
- analytics.js
- Содержимое
index.html. Здесь вbody, подключаем нашmain.js
- В
main.jsзапускаем функции:
- Эти функции объявлены в двух других файлах:
- Запустим наш проект. Нажимаем правой кнопкой мыши по
index.htmlи выбираемopen inи браузер. - В консоли браузера мы видим ошибку:

Сообщение об ошибке связано с тем, что main.js не знает о функции runPlayer. Причина в том, что
два оставшихся скрипта пока не были подключены. Проверив вкладку Network в инструментах
разработчика (F12), мы увидим, что загружаются лишь два файла:

Классическое подключение script
Подключим недостающие файлы таким же образом, как и main.js
❗ Видим, что ошибка в консоли браузера по-прежнему сохранилась.
Но в Network мы видим, что загрузились все файлы:

Проблема возникает из-за порядка подключения скриптов: main.js запускается раньше, чем
player.js, analytics.js, поэтому он не находит их функции.
Решение: изменить порядок подключения. Сначала подключаются скрипты без зависимостей,а уже потом — те, которые от них зависят:
🎉 Теперь в консоли браузера у нас все отображается верно:

Теперь попробуем добавить новый файл в наш проект plugin.js:
Подключаем. Положим его над main.js:
Хотя файл analytics.js также загружен, но в консоли браузера мы не видим run analytics:

Так как все функции из подключённых скриптов попадают в глобальную область видимости(window),
то возможны конфликты имён.
-
В
analytics.jsесть функцияrun. -
Потом мы подключили
plugin.js, в котором также есть свойrun. -
При подключении
plugin.jsего версия перезаписывает предыдущую. -
В итоге при вызове
run()мы запускаем последний загруженный вариант → ошибка.
Решение: определить plugin раньше, чем analytics
Теперь все отображается верно!
Основные проблемы данного метода подключения
1. Порядок подключения
-
Если
main.jsподключить до файлов-зависимостей (analytics.js,player.js), функции из них будут неопределёнными (undefined). -
Сначала должны загружаться зависимости, а уже потом основной скрипт.
2. Глобальная область видимости
-
Все функции и переменные автоматически попадают в глобальный объект
window. -
Это вызывает конфликты имён и переопределение функций.
3. Неочевидные зависимости
-
Трудно понять, откуда берётся та или иная функция.
-
В больших проектах это усложняет поддержку и делает поведение кода непредсказуемым.
Переход к модулям
Современный стандарт решает проблемы классического подключения script. В браузере нативно
поддерживаются ECMAScript Modules.
Модуль – это просто файл. Один скрипт – это один модуль.
🔗 Больше информации:
В index.html оставим только наш главный файл main.js, но укажем тип подключения module:
Теперь в JS-файлах доступны import и export.
Import и Export
importпозволяет импортировать функциональность из других модулей.exportотмечает переменные и функции, которые должны быть доступны вне текущего модуля.
Подробнее про import и export можно почитать в статье
Import-Export
Экспорт по дефолту
Чтобы импортировать функцию, ее нужно сначала экспортировать. Поэтому мы экспортируем нашу функцию
runPlayer.
Этот тип экспорта называется дефолтным (export default) или экспортом по умолчанию. В
каждом файле может быть только один export default. При импорте такого элемента не нужны
фигурные скобки ({}), а имя импортируемого объекта можно выбрать любое — оно не обязано
совпадать с названием в исходном файле.
В файле main.js импортируем runPlayer из player.js.
Именованный экспорт
Теперь попробуем другой способ экспорта на нашей функции run
Этот тип экспорта называется именованным (export). В одном файле можно создавать несколько
именованных экспортов. При импорте обязательно использовать фигурные скобки ({}).Имена
экспортируемых элементов должны совпадать с названиями в исходном файле. Этот тип является
более строгим и в большинстве случаев лучше использовать именно его.
В файле main.js импортируем функцию run из analytics.js.
Импорт модуля без экспорта
Иногда модуль нужен не для того, чтобы отдавать наружу функции или переменные, а только для
выполнения побочных эффектов (side effects) — например, вывод в консоль, показ alert,
инициализация плагина и т.п. В таком случае:
- Модуль ничего не экспортирует.
- В main.js его можно подключить простым импортом:
- Такой импорт просто загружает и выполняет код из файла.
- Всё, что модуль делает «сам по себе» (
console.log,alertи др.) — произойдёт автоматически.
Загрузка модулей
Перейдем в Network и посмотрим, что все наши файлы загрузились:

Как это произошло?
- Браузер загрузил
main.js. - При выполнении видит, что в файле есть импорты.
- Загружает все необходимые зависимости (импортируемые файлы).
- Только после этого начинает выполнять код
main.js.
💡 Это решает проблему порядка подключения — зависимости подгружаются автоматически.
❗Важный момент
Даже если в main.js есть код до строк с import, браузер сначала загрузит и выполнит все
зависимости! Код внутри импортируемых модулей выполнится до любого кода, написанного в main.js
после импортов.
Пример. В player.js напишем:
В main.js:
В консоли браузера мы все равно первым увидим player.js loaded

Конфликты имён и псевдонимы
Для того чтобы продемонстрировать эту проблему, давай в player.js создадим функцию run и
экспортируем ее.
В main.js импортируем run из player.js
- Уже на этапе написания кода
IDEподсвечивает ошибку: имена конфликтуют. - В браузере при запуске получаем аналогичную ошибку.

Решение — псевдонимы (as) Чтобы избежать конфликта, можно задать одному из импортов другое
имя:
✅ Теперь:
runPlayer()запускает плеер,analyticsRun()запускает аналитику,run()изplayer.jsработает без конфликтов,- плюс выполняются побочные эффекты из
plugin.js.
Организация модулей по папкам
Мы хотим разложить файлы по папкам:
player.js→ в папку/player,analytics.jsостаётся рядом сmain.js.
Структура папок теперь выглядит таким образом:
- player.js
- index.html
- main.js
- analytics.js
После переноса IDE начнёт ругаться: файл player.js больше не лежит в той же папке, что и
main.js. Поэтому импорт нужно поправить:
Здесь мы явно говорим: Перейди в папку player и возьми там файл player.js
Импорты внутри модулей
Представим, что плееру нужна аналитика:
- Логично, чтобы
main.jsне импортировал всё подряд. - Пусть сам
player.jsимпортируетanalytics.jsи вызывает её функции.
Пример:
Относительные пути импорта:
./— означает текущая папка.../— означает на уровень выше.
Поэтому в player.js, чтобы достучаться до analytics.js, который лежит на уровень выше, мы пишем:
А запись ./../analytics.js будет избыточной: точку (./) можно убрать, так как мы и так
поднимаемся на уровень вверх.
Наш React и Vite проект
Теперь ты можешь понять больше информации из этих записей:
Обрати внимание, что при импорте createRoot нет точек, это значит, что модуль подтягивается из
папки node_modules. Здесь мы не указываем путь к файлу — createRoot берётся из установленного
пакета react-dom. Так работают все зависимости, которые мы ставим через npm install.
Зарефакторим наш App.tsx, чтобы экспорт был именованным(уберем export default):
Теперь в main.tsx:
Импорт всего модуля
Иногда удобно не перечислять каждый экспорт по отдельности, а забрать весь модуль целиком. В
App.tsx добавим еще один экспорт:
Импорт всего модуля в main.tsx:
Здесь мы импортировали всё содержимое App.tsx в объект appModule с помощью * as. Все экспорты
становятся свойствами этого объекта: appModule.App, appModule.name
Вывод и сравнительная таблица
- Для учебных и маленьких проектов можно использовать
<script>, но нужно следить за порядком и глобальными переменными. - Для современных приложений лучше использовать ES-модули: они решают проблемы зависимостей, конфликтов имён и делают проект более структурированным и предсказуемым.
🏠 Домашнее задание
Задание 1
Создание простой структуры проекта ⭐
Создай проект "Музыкальный плеер" со следующей структурой:
Что нужно сделать:
- Создай папку
music-player - Создай все файлы из структуры выше
- В
index.htmlподключи толькоmain.jsс типомmodule
Задание 2
Создание простых функций 🎵
1. Файл songs.js - список песен
Создай массив песен и экспортируй его по дефолту:
2. Файл player.js - функции плеера
Добавь именованный экспорт в функции управления плеером
3. Файл display.js - функции отображения
Добавь именованный экспорт в функции для показа информации
4. Файл main.js - главный файл
Импортируй все функции и протестируй их работу:
Проверь себя ✅
Открой проект в браузере и убедись, что:
- ✅ Страница загружается без ошибок
- ✅ В консоли выводится приветствие плеера
- ✅ Показывается список всех песен
- ✅ Показываются сообщения о воспроизведении/паузе/остановке
- ✅ Все импорты работают корректно
Ожидаемый результат в консоли:

Задание 3
Псевдонимы
В файле player.js добавь функцию с таким же именем как и в display.js:
Теперь в main.js импортируй обе функции showSong, используя псевдонимы и вызовите обе
функции одна за другой
В итоге вы должны получить результат как в консоли

Задание 4
Импорт всего модуля
Импортируйте весь модуль player.js как player чтобы в файле main.js к нему можно было
обращаться через точку
В итоге вы должны получить результат как и в предыдущем задании 🚀
Задание 5
Side-effect модуль 🎨
Создай файл theme.js, который будет автоматически менять цвет фона страницы
Импортируй его в main.js таким образом, чтобы цвет браузера сменился на темный и в консоли ты
увидел 🎨 Тема загружена

Задание 6
Организация по папкам 📁
Реорганизуй проект, создав папки:
Обнови пути импортов в main.js самостоятельно чтобы в результате получить такой же результат как и
в предыдущем задании
Дополнительное задание (по желанию) 🌟
Попробуй сломать проект и понять, почему:
- Убери
type="module"из HTML - что произойдет? - Измени порядок импортов в
main.js- повлияет ли это на работу? - Удали
exportиз одного файла - какая будет ошибка? - Создай циклическую зависимость (файл А импортирует Б, а Б импортирует А) - что случится?


