Нативные Модули Ecmascript — Первый Обзор



Нативные модули ECMAScript — первый обзор

В этой статье я хочу поделиться переводом статьи о нативной
Модули ECMAScript , которые становятся все более обсуждаемыми среди фронтенд-разработчиков.

Javascript никогда раньше не поддерживал работу с модулями изначально, и нам, фронтенд-разработчикам, всегда приходилось использовать дополнительные инструменты для работы с модулями.

Но только представьте, что скоро вам не понадобится использовать Webpack для создания бандлов модулей.

Представьте себе мир, в котором браузер делает все за вас.

Я хочу рассказать вам подробнее об этих перспективах.

В 2016 году в браузеры и Nodejs было добавлено множество интересных функций и полезностей из новых стандартов, в частности спецификация ECMAScript 2015 .

Сейчас мы столкнулись с ситуацией, когда поддержка среди браузеров близка к 100%:

Нативные модули ECMAScript — первый обзор

Также фактически введено в стандарт Модули ECMAScript (часто называемые модулями ES/ES6).

Это та часть спецификации, реализация которой заняла больше всего времени, и ни один браузер еще не выпустил ее в стабильную версию.

Технический предварительный просмотр Safari 19 и Edge 15 недавно добавили реализации модулей без флагов.

Приближается время, когда мы сможем отказаться от использования привычных бандлов и транспилирующих модулей.

Чтобы лучше понять, как мир фронтенда дошел до этой точки, давайте начнем с истории модулей JS, а затем посмотрим на текущие преимущества и реализации модулей ES6.



Немного истории

Способов соединения модулей было много.

Приведу пример наиболее типичных из них: 1. Просто длинный код внутри тега скрипта.

Например:

  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
   

<!--html--> <script type="application/javascript"> // module1 code // module2 code </script>

2. Разделение логики между файлами и соединение их с помощью тегов скрипта:

/* js */ // module1.js // module1 code // module2.js // module2 code



<!--html--> <script type="application/javascript" src="PATH/module1.js" ></script> <script type="application/javascript" src="PATH/module2.js" ></script>

3. Модуль как функция (например: модуль — функция, которая что-то возвращает; самовызывающая функция или функция-конструктор) + файл/модель приложения, который будет точкой входа для приложения:

// polyfill-vendor.js (function(){ // polyfills-vendor code }()); // module1.js function module1(params){ // module1 code return module1; } // module3.js function module3(params){ this.a = params.a; } module3.prototype.getA = function(){ return this.a; }; // app.js var APP = {}; if(isModule1Needed){ APP.module1 = module1({param1:1}); } APP.module3 = new module3({a: 42});



<!--html--> <script type="application/javascript" src="PATH/polyfill-vendor.js" ></script> <script type="application/javascript" src="PATH/module1.js" ></script> <script type="application/javascript" src="PATH/module2.js" ></script> <script type="application/javascript" src="PATH/app.js" ></script>

Помимо всего этого, сообщество Frontend изобрело множество вариаций и новых способов, которые добавили разнообразия в это торжество анархии.

Основная идея состоит в том, чтобы предоставить систему, которая позволит вам просто включить одну ссылку на JS-файл, например:

<!--html--> <script type="application/javascript" src="PATH/app.js" ></script>

Но все сводилось к тому, что разработчики выбрали сторону бандлеров — систем сборки кода.

Далее мы предлагаем рассмотреть основные реализации модулей на JavaScript.

Определение асинхронного модуля ( АМД )

Этот подход широко реализован в библиотеке.

ТребоватьJS и в таких инструментах, как r.js для создания результирующего пакета.

Общий синтаксис:

// polyfill-vendor.js define(function () { // polyfills-vendor code }); // module1.js define(function () { // module1 code return module1; }); // module2.js define(function (params) { var a = params.a; function getA(){ return a; } return { getA: getA } }); // app.js define(['PATH/polyfill-vendor'] , function () { define(['PATH/module1', 'PATH/module2'] , function (module1, module2) { var APP = {}; if(isModule1Needed){ APP.module1 = module1({param1:1}); } APP.module2 = new module2({a: 42}); }); });



CommonJS

Это основной формат модуля в экосистеме Node.js. Одним из основных инструментов создания бандлов для клиентских устройств является Просматривать .

Особенностью этого стандарта является то, что для каждого модуля предусмотрена отдельная область применения.

Это позволяет избежать непреднамеренной утечки глобальной области видимости и глобальных переменных.

Пример:

// polyfill-vendor.js // polyfills-vendor code // module1.js // module1 code module.exports= module1; // module2.js module.exports= function(params){ const a = params.a; return { getA: function(){ return a; } }; }; // app.js require('PATH/polyfill-vendor'); const module1 = require('PATH/module1'); const module2 = require('PATH/module2'); const APP = {}; if(isModule1Needed){ APP.module1 = module1({param1:1}); } APP.module2 = new module2({a: 42});



Модули ECMAScript (также известные как ES6/ES2015/родные модули JavaScript)

Еще один способ работы с модулями пришел к нам с ES2015. В новом стандарте представлен новый синтаксис и функции для удовлетворения потребностей внешнего интерфейса, такие как:
  • отдельные области действия модуля
  • строгий режим по умолчанию
  • циклические зависимости
  • возможность легко взломать код, соблюдая спецификацию
Существует множество реализаций загрузчика, компиляторов и подходов, которые поддерживают одну или несколько из этих систем.

Например:



Инструменты

Сегодня в JavaScript мы привыкли использовать различные инструменты для объединения модулей.

Если мы говорим о модулях ECMAScript, вы можете использовать один из следующих:

Обычно инструмент предоставляет интерфейс CLI и возможность настройки конфигурации для создания пакетов из ваших файлов JS. Он получает точки входа и набор файлов.

Обычно такие инструменты автоматически добавляют «use strict».

Некоторые из этих инструментов также могут транспилировать код, чтобы он работал во всех необходимых средах (старые браузеры, Node.js и т. д.).

Давайте посмотрим на упрощенную конфигурацию WebPack, которая устанавливает точку входа и использует Babel для передачи файлов JS:

// webpack.config.js const path = require('path'); module.exports = { entry: path.resolve('src', 'webpack.entry.js'), output: { path: path.resolve('build'), filename: 'main.js', publicPath: '/' }, module: { loaders: { "test": /\.

js?$/, "exclude": /node_modules/, "loader": "babel" } } };

Конфиг состоит из основных частей:

  1. мы начинаем с файла webpack.entry.js
  2. используем загрузчик Babel для всех JS файлов (то есть код будет транспилироваться в зависимости от пресетов/плагинов + будет сгенерирован бандл)
  3. Результат помещается в файл main.js.
В этом случае обычно файл index.html будет содержать следующее:

<script src="build/main.js"></script>

И ваше приложение использует пакеты/транспилируемый JS-код. Это общий подход к работе с бандлерами, давайте посмотрим, как заставить его работать в браузере без каких-либо бандлеров.



Как заставить модули JavaScript работать в браузере



Поддержка браузера

Сегодня каждый из современных браузеров имеет поддержку модулей ES6:

Нативные модули ECMAScript — первый обзор



Где я могу проверить

Как вы видели, в настоящее время можно протестировать собственные модули JS в Safari Technology Preview 19+ и EDGE 15 Preview Build 14342+.

Давайте скачаем и попробуем модули в действии.



Модули ES доступны в Firefox

Вы можете скачать Firefox Ночной , а это значит, что модули скоро появятся в Версия для разработчиков FF , а затем в стабильной версии браузера.

Чтобы включить модули ES:

  • откройте страницу `about:config`
  • нажмите «Я принимаю риск!»
  • найдите флаг `dom.moduleScripts.enabled`
  • дважды щелкните, чтобы изменить значение флага на true
И всё, теперь у вас есть доступ к ES модулям в Firefox.

Предварительная версия технологии Safari с доступными модулями ES

Если вы используете MacOS, просто загрузите последнюю версию Safari Technology Preview (TP) с сайта разработчик.

apple.com .

Установите и откройте его.

Начиная с Предварительная версия технологии Safari 21+ Модули ES включены по умолчанию.

Если это Safari TP 19 или 20, убедитесь, что модули ES6 включены: откройте меню «Разработка» → «Экспериментальные функции» → «Модули ES6».



Нативные модули ECMAScript — первый обзор

Другой вариант - загрузите последнюю версию Webkit Nightly и поиграй с ним.



EDGE 15 — включить ES модули

Ты можешь скачать бесплатную виртуальную машину от Microsoft .

Просто выберите виртуальную машину (ВМ) «Microsoft Edge on Win 10 Preview (15.XXXXX)» и, например, «Virtual Box» (также бесплатно) в качестве платформы.

Установите и запустите виртуальную машину, затем откройте браузер EDGE. Перейдите на страницу about:flags и установите флажок Включить экспериментальные функции JavaScript.

Нативные модули ECMAScript — первый обзор

Вот и все, теперь у вас есть несколько сред, в которых вы можете играть с собственной реализацией модулей ECMAScript.

Отличия родных и собранных модулей

Начнем с нативных возможностей модулей:
  1. Каждый модуль имеет свою собственную область действия, которая не является глобальной.

  2. Они всегда находятся в строгом режиме, даже если директива use strict не указана.

  3. Модуль может импортировать другие модули, используя директивы импорта .

  4. Модуль можно экспортировать с помощью экспорт .

Пока мы не увидели особо существенных отличий от привычных нам бандлеров.

Большая разница в том, что точка входа должна быть указана в браузере.

Вы должны предоставить тегу скрипта определенный атрибут type="module", например:

<script type= "module" scr= "PATH/file.js" ></script>

Это сообщает браузеру, что ваш скрипт может содержать импорт других скриптов, и с ними следует обращаться соответствующим образом.

Главный вопрос, который здесь возникает:

Почему интерпретатор JavaScript не может определять модули, если файл уже является модулем?
Одна из причин — нативные модули по умолчанию находятся в строгом режиме, а классические скрипты — нет:
  1. Допустим, интерпретатор анализирует файл, предполагая, что это классический скрипт в нестрогом режиме;
  2. затем он находит директиву «импорт\экспорт»;
  3. в этом случае он должен начать с начала, чтобы снова разобрать весь код в строгом режиме.

Другая причина заключается в том, что один и тот же файл может быть действительным без строгого режима и недействительным с ним.

Тогда валидность зависит от того, как она интерпретируется, что приводит к неожиданным проблемам.

Определение типа файла, который вы ожидаете загрузить, открывает множество возможностей для оптимизации (например, загрузка импортированных файлов параллельно/перед анализом остальной части html-файла).

ты можешь найти Некоторые примеры , используется JavaScript-движками Microsoft Chakra для модулей ES .



Способ Node.js указать файл как модуль

Среда Node.js отличается от браузеров, и использование тега script type="module" не особенно подходит. В настоящее время все еще продолжается спор, как лучше это сделать .

Некоторые решения были отклонены сообществом:

  1. добавить «использовать модуль» в каждый файл;
  2. метаданные в package.json.
Другие варианты пока рассматриваются (спасибо).

@bmeck за подсказку):

  1. определение, является ли файл модулем ES;
  2. новое расширение файла для модулей ES6 .

    mjs, которое будет использоваться в качестве запасного варианта, если предыдущая версия не будет работать.

У каждого метода есть свои плюсы и минусы, и на данный момент до сих пор нет однозначного ответа, какой именно.

путь Node.js будет идти .



Простой пример нативного модуля

Сначала создадим простая демонстрация (вы можете запустить его в установленных ранее браузерах для проверки модулей).

Итак, это будет простой модуль, который импортирует другой и вызывает из него метод. Первым шагом является включение файла с помощью:

<script type="module"/>



<!--index.html--> <!DOCTYPE html> <html> <head> <script type="module" src="main.js"></script> </head> <body> </body> </html>

Вот файл модуля:

// main.js import utils from ".

/utils.js"; utils.alert(` JavaScript modules work in this browser: https://blog.whatwg.org/js-modules `);

И наконец, импортные утилиты:

// utils.js export default { alert: (msg)=>{ alert(msg); } };

Как вы, возможно, заметили, мы оставили расширение файла .

js при использовании директивы импорта.

Это еще одно отличие от поведения сборщиков — нативные модули по умолчанию не добавляют расширения .

js. Во-вторых, давайте проверим область видимости модуля ( демо ):

var x = 1; alert(x === window.x);//false alert(this === undefined);// true

В-третьих, мы проверим, что собственные модули по умолчанию находятся в строгом режиме.

Например, строгий режим предотвращает удаление простых переменных.

Следующая демонстрация показывает, что в модуле есть сообщение об ошибке:

// module.js var x; delete x; // !!! syntax error alert(` THIS ALERT SHOULDN'T be executed, the error is expected as the module's scripts are in the strict mode by default `); // classic.js var x; delete x; // !!! syntax error alert(` THIS ALERT SHOULD be executed, as you can delete variables outside of the strict mode `);

Строгий режим нельзя обойти в собственных модулях.

Общий:

  • Расширение .

    js нельзя опустить;

  • область действия не глобальная, это ни к кому не относится;
  • Нативные модули по умолчанию находятся в строгом режиме (больше не нужно писать «use strict»).



Встроенный модуль в теге скрипта

Как и в обычные скрипты, вы можете встраивать код вместо того, чтобы разбивать его на отдельные файлы.

В предыдущей демонстрации вы можете просто вставить файл main.js непосредственно в тег скрипта type="module", который приведет к такому же поведению :

<script type="module"> import utils from ".

/utils.js"; utils.alert(` JavaScript modules work in this browser: https://blog.whatwg.org/js-modules `); </script>

Общий:

  • script type="module" можно использовать либо для загрузки и выполнения внешнего файла, либо для выполнения встроенного кода внутри тега скрипта.



Как браузер загружает и выполняет модули

Нативные модули (асинхронные) по умолчанию имеют отложенное поведение скрипта.

Чтобы понять это, мы можем представить каждый тег скрипта type="module" с атрибутом defer и без него.

Вот изображение из спецификации, которое объясняет поведение :

Нативные модули ECMAScript — первый обзор

Это означает, что по умолчанию скрипты в модулях неблокируются, загружаются параллельно и выполняются, когда страница завершает анализ html. Вы можете изменить это поведение, добавив атрибут async, тогда скрипт будет выполнен сразу после загрузки.

Основное различие между нативными модулями и обычными скриптами заключается в том, что обычные скрипты загружаются и выполняются немедленно, блокируя парсинг html. Чтобы представить это, посмотрите демонстрация с различными параметрами атрибутов в теге скрипта , где сначала будет выполнен обычный скрипт без атрибутов defer\async:

<!DOCTYPE html> <html> <head> <script type="module" src=".

/script1.js"></script> <script src=".

/script2.js"></script> <script defer src=".

/script3.js"></script> <script async src=".

/script4.js"></script> <script type="module" async src=".

/script5.js"></script> </head> <body> </body> </html>

Порядок загрузки зависит от реализации браузера, размера скриптов, количества импортируемых скриптов и т. д. Общий:

  • модули по умолчанию асинхронны и ведут себя как отложенные скрипты.

Мы вступаем в эпоху встроенной поддержки модулей в JavaScript. JS прошел долгий путь в своем развитии и наконец достиг этой точки.

Это, пожалуй, одна из самых долгожданных и востребованных функций.

Никакое количество синтаксического сахара или новых языковых конструкций не сравнится с этим новым стандартом.

Все вышесказанное дано для первого знакомства с нативными модулями ECMAScript. В следующей статье мы рассмотрим, как взаимодействуют модули, определяя поддержку в браузерах, особенности и отличия от обычных бандлов и т.д. Если вы хотите узнать больше сейчас, я предлагаю вам перейти по ссылкам:

Честно говоря, когда я впервые попробовал нативные модули, и они работали в браузере, я почувствовал то, чего не ощущал с появлением таких возможностей языка, как функции const/let/arrow и прочих новомодных возможностей, когда они начинались.

работа непосредственно в браузерах.

Надеюсь, вы так же, как и я, воодушевлены добавлением в браузеры встроенной функциональности модулей.



Другие статьи автора на эту тему



От переводчика

Я Frontend-разработчик в команде Avia. Туту.

ру .

В настоящее время в наших проектах в качестве сборщика используется Webpack. Существует устаревший код и старые проекты с RequireJS. Нативные модули очень интересны и мы их очень ждём, тем более, что все наши проекты мы уже перевели на HTTP/2. Конечно, полностью без бандлеров мы не собираемся обходиться, так как у нас во всех проектах большое количество модулей.

Но появление собственных модулей может изменить рабочий процесс сборки и развертывания.

Теги: #JavaScript #frontend #babel #webpack #будущее #стандарты #разработка веб-сайтов #JavaScript #программирование #браузеры

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.