Модульность кода
1. Модульность кода
Концепция модулей как способа организации кода существовала давно. С ростом проекта и его кодовой базы ее пытаются разбить на файлы, в каждом из которых описывается отдельный функционал.
Модульный код помогает в организации, обслуживании, тестировании и, самое главное, управлении зависимостями. Наиболее важные преимущества модулей - это поддерживаемость, пространство имен и повторное использование.
Поддерживаемость — хорошо разработанный модуль призван максимально снизить зависимость от других частей кода. Это позволит расширять функционал приложения не опасаясь нарушить его работу в целом. Обновление одного модуля намного проще, если модуль самодостаточен.
Пространство имен — переменные, не входящие в область видимости функции, являются глобальными. Из-за этого обычно происходит загрязнение пространства имен, где полностью несвязанный код разделяет глобальные переменные. Модули позволяют избежать загрязнения пространства имен, создавая отдельную область видимости для переменных.
Повторное использование — все разработчики копировали готовый код в новые проекты, изменяя его под специфику проекта. Это, очевидно, огромная трата времени. Намного лучше когда есть модуль, который можно повторно использовать снова и снова без необходимости знать что-либо об окружении в котором он используется.
1.1. Сборка модулей
Сборка модулей — это процесс конкатенации группы модулей и их зависимостей в один или группу файлов.
Обычно код делят на папки и файлы, к тому же необходимо подключить внешние библиотеки. В результате каждый из этих файлов должен быть включен в основной HTML-файл в теге script
, который затем загружается браузером.
Наличие отдельных тегов script
для каждого файла означает, что браузер будет загружать каждый файл по отдельности, что негативно сказывается на скорости загрузки страницы (HTTP/2 немного помогает с решением этой проблемы). Чтобы обойти эту проблему, файлы объединяются в один или пару файлов, чтобы уменьшить количество запросов. Но остается проблема управления зависимостями между модулями.
Если используются системы модулей, которые браузеры не поддерживают, такие как CommonJS
или ESM
, необходимо использовать инструмент для их преобразования в правильно упорядоченный, доступный браузеру код. Именно здесь вступают в действие Webpack
и другие бандлеры (от английского bundle).
2. CommonJS модули
CommonJS — модульная система, используемая в Node.js. Модули имеют компактный синтаксис, предназначены для синхронной загрузки и, в основном, используются на сервере и не работают в браузере по умолчанию.
CommonJS-модуль - это многократно используемый фрагмент JS-кода, который экспортирует определенные объекты, делая их доступными для других модулей.
Каждый JS-файл хранит код в уникальном контексте модуля. Для того чтобы описать интерфейс модуля, используется объект module.exports
, значение которого будет доступно для использования другими модулями при импорте.
Для того чтобы получить интерфейс модуля в коде (импортировать), используется функция require('путь-к-модулю')
. Результатом своего выполнения require
вернет интерфейс модуля — то что в модуле указано в module.exports
.
Есть два очевидных преимущества этого подхода:
Предотвращение загрязнения глобального пространства имен
Явное указание зависимостей
3. ECMAScript Modules (ESM)
До недавнего времени в языке не было встроенной модульной системы. ESM имеют декларативный синтаксис и возможность асинхронной загрузки.
Самое важное отличие ESM заключается в том, что они разработаны с учетом статического анализа. Это значит, что при импорте модулей, импорт обрабатывается во время компиляции, то есть до запуска скрипта. Это позволяет удалять экспорт, который не используется другими модулями, прежде чем запускать скрипт, что может привести к значительной экономии веса JS-файла, уменьшив нагрузку на браузер.
3.1. Синтаксис
Каждый модуль импортирует необходимые ему зависимости и экспортирует все, что должно быть импортировано другими модулями. Операции экспорта сущностей и импорта интерфейса модуля реализованы конструкциями import from
и export
.
3.2. Named export
Модуль может экспортировать несколько сущностей, которые отличаются своими именами и называются именованными экспортами. Чтобы импортировать их в другой модуль, необходимо знать имена экспортируемых сущностей, которые мы хотим импортировать.
Первый способ - это использовать ключевое слово export
перед всеми сущностями, которые необходимо экспортировать. Они будут добавлены как свойства в экспортируемый объект. При импорте мы деструктуризируем свойства из импортируемого объекта.
Второй способ - это явно указать объект со свойствами для экспорта.
Следующий синтаксис импортирует все экспорты модуля как объект с указанным именем.
3.3. Default export
Часто модуль экспортирует всего одну сущность, такой экспорт удобен для импорта. Экспорт по умолчанию — самое главное экспортируемое значение, которое может быть чем угодно: переменной, функцией, классом и т. д.
Используйте именованный экспорт, когда необходимо экспортировать несколько сущностей, а экспорт по умолчанию - при экспорте одной сущности. Хотя и можно использовать экспорт по умолчанию и именованный экспорт в одном файле, хорошей практикой будет выбрать только один стиль для каждого модуля.
4. Дополнительные материалы
Last updated