О модулях JavaScript, форматах, загрузчиках и сборщиках модулей за 10 минут
57К открытий58К показов
Несмотря на то, что новые языки программирования появляются каждый год, JavaScript остаётся одним из самых распространённых и любимых программистами. И как и любой современный язык, он стремительно развивается, что делает изучение его с нуля очень непростой задачей. В этом материале простым языком рассказывается о том, как в JavaScript устроена работа с модулями. Статья может не только помочь новичкам понять, что происходит, но и освежить знания основ у тех, кто уже работает с JS.
Разработка с использованием современных технологий JavaScript может ошеломлять. Работая над проектом, ты легко можешь задаться вопросом, для чего же нужны новые механизмы и инструменты.
Для чего предназначены Webpack и SystemJS? Что значит AMD, UMD или CommonJS? Какое отношение они имеют друг к другу и зачем вообще их использовать?
В этой статье речь пойдёт о различии между модулями JavaScript, а также о форматах, загрузчиках и сборщиках модулей. Это не подробное руководство по использованию каких-либо инструментов или паттернов, а краткий обзор, призванный дать общее понятие о концепции современного JavaScript.
Итак, приступим.
Что такое модуль?
Модуль — это переиспользуемая часть кода, содержащая в себе детали реализации и предоставляющая открытое API, что позволяет легко загрузить её и использовать в другом коде.
Зачем нужны модули?
Технически код можно написать и без использования модулей. Модули — это паттерн, который в разных формах и на разных языках используется разработчиками с 60-х и 70-х годов.
В идеале, модули JavaScript позволяют нам:
- абстрагировать код, передавая функциональные возможности сторонним библиотекам, так что нам не придётся разбираться во всех сложностях их реализации;
- инкапсулировать код, скрывая его внутри модуля, если не хотим, чтобы его изменяли;
- переиспользовать код, избавляясь от необходимости писать одно и то же снова и снова;
- управлять зависимостями, легко изменяя зависимости без необходимости переписывать наш код.
Паттерны модулей в ES5
ECMAScript 5 и более ранние версии не были спроектированы с учётом модулей. Со временем разработчики нашли различные возможности симулировать модульную архитектуру на JavaScript.
Прим. перев. Senior-разработчики компании Noveo говорят, что помнят, как это было: как они проходили путь от работы без модулей к первым попыткам написать их самостоятельно, потом использовать чужие наработки… Ну а все системы, перечисленные ниже, они знают не понаслышке. Эх, были времена!
Чтобы дать представление о том, как выглядят такие паттерны, давайте взглянем на два из них: мгновенно вызываемая функция (Immediately Invoked Function Expressions) и выявление модуля (Revealing Module).
Немедленно вызываемая функция (Immediately Invoked Function Expression или IIFE)
Немедленно вызываемая функция (IIFE) — анонимная функция, которая вызывается сразу после объявления. Обратите внимание: функция окружена скобками. В JavaScript строка, начинающаяся со слова function, воспринимается как объявление функции:
Мгновенный вызов объявления функции выдаёт ошибку:
Помещение функции в скобки делает это функциональным выражением:
Функциональное выражение возвращает нам функцию, так что мы можем тут же к ней обратиться:
Мгновенно вызываемые функции позволяют нам:
- полностью инкапсулировать код в IIFE, так что нам не придётся разбираться, как работает код IIFE;
- определять переменные внутри IIFE, чтобы они не засоряли глобальную область видимости (переменные, объявленные внутри IIFE, остаются в рамках замкнутого выражения).
Однако они не дают нам механизма управления зависимостями.
Паттерн выявления модуля (Revealing Module)
Паттерн выявления модуля схож с IIFE, но здесь мы присваиваем возвращённое значение переменной:
Заметьте, что здесь нет необходимости в скобках, так как слово function находится не в начале строки.
Теперь мы можем обратиться к API модуля через переменную:
Вместо синглтона модуль может выступать и как функция-конструктор:
Обратите внимание: мы не запускаем функцию при её объявлении, вместо этого мы инициализируем модуль при помощи функции-конструктора Module
для доступа к внешнему API
Паттерн выявления модуля предоставляет те же преимущества, что и IIFE, но опять же не даёт возможности управлять зависимостями.
С развитием JavaScript появлялись разные синтаксические возможности определения модулей, и у каждого были свои сильные и слабые стороны.
Форматы модулей
Формат модуля — это синтаксис, который используется для его определения.
До создания ECMAScript 6, или ES2015, в JavaScript не было официального синтаксиса для определения модулей. А значит, опытные разработчики предлагали разные форматы определения.
Вот несколько наиболее известных и широко используемых:
- асинхронное определение модуля (Asynchronous Module Definition или AMD);
- CommonJS;
- универсальное определение модуля (Universal Module Definition или UMD);
- System.register;
- формат модуля ES6.
Давайте рассмотрим каждый из них, чтобы вы смогли распознать их по синтаксису.
Асинхронное определение модуля (AMD)
Формат AMD используется в браузерах и применяет для определения модулей функцию define:
Формат CommonJS
Формат CommonJS применяется в Node.js и использует для определения зависимостей и модулей require и module.exports:
Универсальное определение модуля (UMD)
Формат UMD может быть использован как в браузере, так и в Node.js.
System.registerА
Формат System.register был разработан для поддержки синтаксиса модулей ES6 в ES5:
Формат модулей ES6
В ES6 JavaScript уже поддерживает нативный формат модулей.
Он использует токен export для экспорта публичного API модуля:
и токен import для импорта частей, которые модуль экспортирует:
Мы можем даже присваивать импорту алиас, используя as:
или загружать сразу весь модуль:
Формат также поддерживает экспорт по умолчанию:
который можно импортировать, например, так:
Вы можете экспортировать не только функции, но и всё, что пожелаете:
К сожалению, нативный формат модулей пока поддерживают не все браузеры.
Мы можем использовать формат модулей ES6 уже сегодня, но для этого потребуется компилятор наподобие Babel, который будет переводить наш код в формат ES5, такой, как AMD или CommonJS, перед тем, как код будет запущен в браузере.
Загрузчики модулей
Загрузчик модулей интерпретирует и загружает модуль, написанный в определённом формате.
Загрузчик модуля запускается в среде исполнения:
- вы загружаете загрузчик модуля в браузере;
- вы сообщаете загрузчику, какой главный файл приложения запустить;
- модуль скачивает и интерпретирует главный файл приложения;
- загрузчик модулей скачивает файлы по мере необходимости.
Если вы откроете вкладку «Сеть» в консоли разработчика на своём браузере, вы увидите, что многие файлы были загружены по запросу загрузчика модулей.
Вот несколько популярных загрузчиков:
- RequireJS: загрузчик модулей в формате AMD ;
- SystemJS: загрузчик модулей в форматах AMD, CommonJS, UMD и System.register format.
Сборщики модулей
Сборщик модулей заменяет собой загрузчик модулей. Однако в отличие от загрузчика модулей, сборщик модулей запускается при сборке:
- вы запускаете сборщик модулей для создания файла пакета во время сборки (например, bundle.js);
- и загружаете пакет в браузер.
Если вы откроете вкладку «Сеть» в консоли разработчика на своём браузере, вы увидите, что загружен только один файл. Таким образом, отпадает необходимость в загрузчике модулей: весь код включён в один пакет.
Пара популярных сборщиков:
- Browserify: сборщик для модулей CommonJS;
- Webpack: сборщик для модулей AMD, CommonJS, ES6.
Подводим итоги
Чтобы лучше разобраться в инструментах современной среды разработки на JavaScript, важно понимать разницу между модулями, форматами, загрузчиками и сборщиками модулей.
Модуль — это переиспользуемая часть кода, содержащая в себе детали реализации и предоставляющая открытое API, что позволяет легко загрузить её и использовать в другом коде.
Формат модуля — это синтаксис, который используется для определения модулей. В прошлом возникали разные форматы: AMD, CommonJS, UMD и System.register нативный формат модулей появился в ES6.
Загрузчик модуля интерпретирует и загружает модуль, написанный в определённом формате, в время выполнения (в браузере). Распространённые — RequireJS и SystemJS.
Сборщик модуля заменяет загрузчик модулей и создаёт пакет, содержащий весь код, во время сборки. Популярные примеры — Browserify и Webpack.
Вот и всё — теперь у вас достаточно знаний для понимания современной разработки на JavaScript. В следующий раз, когда ваш компилятор TypeScript спросит, какой формат модулей вы хотите использовать, вы уже не будете гадать, что бы это значило. А если такое произойдет — просто перечитайте эту статью.
Отличного дня и программируйте с удовольствием!
За перевод материала выражаем благодарность международной IT-компании Noveo.
57К открытий58К показов