В этой статье я хочу поделиться переводом статьи о нативной Модули ECMAScript , которые становятся все более обсуждаемыми среди фронтенд-разработчиков.
Javascript никогда раньше не поддерживал работу с модулями изначально, и нам, фронтенд-разработчикам, всегда приходилось использовать дополнительные инструменты для работы с модулями.
Но только представьте, что скоро вам не понадобится использовать Webpack для создания бандлов модулей.
Представьте себе мир, в котором браузер делает все за вас.
Я хочу рассказать вам подробнее об этих перспективах.
В 2016 году в браузеры и Nodejs было добавлено множество интересных функций и полезностей из новых стандартов, в частности спецификация ECMAScript 2015 .
Сейчас мы столкнулись с ситуацией, когда поддержка среди браузеров близка к 100%:
Также фактически введено в стандарт Модули ECMAScript (часто называемые модулями ES/ES6).
Это та часть спецификации, реализация которой заняла больше всего времени, и ни один браузер еще не выпустил ее в стабильную версию.
Технический предварительный просмотр Safari 19 и Edge 15 недавно добавили реализации модулей без флагов.
Приближается время, когда мы сможем отказаться от использования привычных бандлов и транспилирующих модулей.
Чтобы лучше понять, как мир фронтенда дошел до этой точки, давайте начнем с истории модулей JS, а затем посмотрим на текущие преимущества и реализации модулей ES6.
Немного истории
Способов соединения модулей было много.Приведу пример наиболее типичных из них: 1. Просто длинный код внутри тега скрипта.
Например:
2. Разделение логики между файлами и соединение их с помощью тегов скрипта:<!--html--> <script type="application/javascript"> // module1 code // module2 code </script>
/* 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, вы можете использовать один из следующих:
- Свернуть
- Трейсер Компилятор
- Вавилон , в частности, плагин для конвертация модулей ES2015 в CommonJS
- Веб-пакет 2 с помощью Tree Shaking (удаление неиспользуемого кода)
- Машинопись - как транспилятор
Обычно такие инструменты автоматически добавляют «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"
}
}
};
Конфиг состоит из основных частей:
- мы начинаем с файла webpack.entry.js
- используем загрузчик Babel для всех JS файлов (то есть код будет транспилироваться в зависимости от пресетов/плагинов + будет сгенерирован бандл)
- Результат помещается в файл main.js.
<script src="build/main.js"></script>
И ваше приложение использует пакеты/транспилируемый JS-код. Это общий подход к работе с бандлерами, давайте посмотрим, как заставить его работать в браузере без каких-либо бандлеров.
Как заставить модули JavaScript работать в браузере
Поддержка браузера
Сегодня каждый из современных браузеров имеет поддержку модулей ES6:- Fire Fox - реализовано, доступно под флагом в Firefox 54+
- Хром - в разработке
- КРАЙ - реализовано, доступно под флагом в предварительной версии EDGE 15, сборка 14342+.
- Вебкит - реализовано, доступно по умолчанию Safari Technology Preview 21+
- Node.js — на рассмотрении, требуют дополнительного обсуждения
Где я могу проверить
Как вы видели, в настоящее время можно протестировать собственные модули JS в Safari Technology Preview 19+ и EDGE 15 Preview Build 14342+.Давайте скачаем и попробуем модули в действии.
Модули ES доступны в Firefox
Вы можете скачать Firefox Ночной , а это значит, что модули скоро появятся в Версия для разработчиков FF , а затем в стабильной версии браузера.Чтобы включить модули ES:
- откройте страницу `about:config`
- нажмите «Я принимаю риск!»
- найдите флаг `dom.moduleScripts.enabled`
- дважды щелкните, чтобы изменить значение флага на true
Предварительная версия технологии Safari с доступными модулями ES
Если вы используете MacOS, просто загрузите последнюю версию Safari Technology Preview (TP) с сайта разработчик.apple.com
.Установите и откройте его.
Начиная с Предварительная версия технологии Safari 21+ Модули ES включены по умолчанию.
Если это Safari TP 19 или 20, убедитесь, что модули ES6 включены: откройте меню «Разработка» → «Экспериментальные функции» → «Модули ES6».
Другой вариант - загрузите последнюю версию Webkit Nightly и поиграй с ним.
EDGE 15 — включить ES модули
Ты можешь скачать бесплатную виртуальную машину от Microsoft .Просто выберите виртуальную машину (ВМ) «Microsoft Edge on Win 10 Preview (15.XXXXX)» и, например, «Virtual Box» (также бесплатно) в качестве платформы.
Установите и запустите виртуальную машину, затем откройте браузер EDGE.
Перейдите на страницу about:flags и установите флажок Включить экспериментальные функции JavaScript.
Вот и все, теперь у вас есть несколько сред, в которых вы можете играть с собственной реализацией модулей ECMAScript.
Отличия родных и собранных модулей
Начнем с нативных возможностей модулей:- Каждый модуль имеет свою собственную область действия, которая не является глобальной.
- Они всегда находятся в строгом режиме, даже если директива use strict не указана.
- Модуль может импортировать другие модули, используя директивы импорта .
- Модуль можно экспортировать с помощью экспорт .
Большая разница в том, что точка входа должна быть указана в браузере.
Вы должны предоставить тегу скрипта определенный атрибут type="module", например: <script type= "module" scr= "PATH/file.js" ></script>
Это сообщает браузеру, что ваш скрипт может содержать импорт других скриптов, и с ними следует обращаться соответствующим образом.
Главный вопрос, который здесь возникает:
Почему интерпретатор JavaScript не может определять модули, если файл уже является модулем?Одна из причин — нативные модули по умолчанию находятся в строгом режиме, а классические скрипты — нет:
- Допустим, интерпретатор анализирует файл, предполагая, что это классический скрипт в нестрогом режиме;
- затем он находит директиву «импорт\экспорт»;
- в этом случае он должен начать с начала, чтобы снова разобрать весь код в строгом режиме.
Тогда валидность зависит от того, как она интерпретируется, что приводит к неожиданным проблемам.
Определение типа файла, который вы ожидаете загрузить, открывает множество возможностей для оптимизации (например, загрузка импортированных файлов параллельно/перед анализом остальной части html-файла).
ты можешь найти Некоторые примеры , используется JavaScript-движками Microsoft Chakra для модулей ES .
Способ Node.js указать файл как модуль
Среда Node.js отличается от браузеров, и использование тега script type="module" не особенно подходит. В настоящее время все еще продолжается спор, как лучше это сделать .Некоторые решения были отклонены сообществом:
- добавить «использовать модуль» в каждый файл;
- метаданные в package.json.
@bmeck за подсказку):
- определение, является ли файл модулем ES;
- новое расширение файла для модулей ES6 .
mjs, которое будет использоваться в качестве запасного варианта, если предыдущая версия не будет работать.
Простой пример нативного модуля
Сначала создадим простая демонстрация (вы можете запустить его в установленных ранее браузерах для проверки модулей).
Итак, это будет простой модуль, который импортирует другой и вызывает из него метод. Первым шагом является включение файла с помощью: <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 и без него.
Вот изображение из спецификации, которое объясняет поведение :
Это означает, что по умолчанию скрипты в модулях неблокируются, загружаются параллельно и выполняются, когда страница завершает анализ 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>
Порядок загрузки зависит от реализации браузера, размера скриптов, количества импортируемых скриптов и т. д. Общий:
- модули по умолчанию асинхронны и ведут себя как отложенные скрипты.
Это, пожалуй, одна из самых долгожданных и востребованных функций.
Никакое количество синтаксического сахара или новых языковых конструкций не сравнится с этим новым стандартом.
Все вышесказанное дано для первого знакомства с нативными модулями ECMAScript. В следующей статье мы рассмотрим, как взаимодействуют модули, определяя поддержку в браузерах, особенности и отличия от обычных бандлов и т.д. Если вы хотите узнать больше сейчас, я предлагаю вам перейти по ссылкам:
- Модули являются частью книг по JavaScript доктора Акселя Раушмайера
- Предложение `script type="module" ` от Доменика Дениколы
- Живой стандарт HTML, раздел «Сценарии»
работа непосредственно в браузерах.
Надеюсь, вы так же, как и я, воодушевлены добавлением в браузеры встроенной функциональности модулей.
Другие статьи автора на эту тему
- Собственные модули ECMAScript: динамический импорт()
- Собственные модули ECMAScript: атрибут nomodule для миграции
- Нативные модули ECMAScript: новые возможности и отличия от модулей Webpack
От переводчика
Я Frontend-разработчик в команде Avia. Туту.ру
.В настоящее время в наших проектах в качестве сборщика используется Webpack. Существует устаревший код и старые проекты с RequireJS. Нативные модули очень интересны и мы их очень ждём, тем более, что все наши проекты мы уже перевели на HTTP/2. Конечно, полностью без бандлеров мы не собираемся обходиться, так как у нас во всех проектах большое количество модулей.
Но появление собственных модулей может изменить рабочий процесс сборки и развертывания.
Теги: #JavaScript #frontend #babel #webpack #будущее #стандарты #разработка веб-сайтов #JavaScript #программирование #браузеры
-
Митчелл, Питер Деннис
19 Oct, 24 -
Логотип Google На День Рождения!
19 Oct, 24 -
Покупка В Apple Store С Доставкой По России.
19 Oct, 24 -
Интеллектуальный Школьный Совет
19 Oct, 24 -
Версия Для Печати Таблицы Контейнера Stl
19 Oct, 24