Эта статья покажет вам, как вы можете использовать ES-модули в браузере сегодня.
До недавнего времени в JavaScript не было понятия модулей. Было невозможно напрямую ссылаться или включать один файл JavaScript в другой. И по мере того, как приложения увеличивались в размерах и сложности, это усложняло написание JavaScript для браузера.
Одним из распространенных решений является загрузка произвольных сценариев на веб-странице с использованием тегов <script>
. Однако это приносит свои проблемы. Например, каждый сценарий инициирует HTTP-запрос, блокирующий рендеринг, что может привести к тому, что JS-страницы будут работать медленно и медленно. Управление зависимостями также усложняется, поскольку порядок загрузки имеет значение.
ES6 (ES2015) каким-то образом решил эту ситуацию, внедрив единый стандарт модулей. (Вы можете прочитать больше о модулях ES6 здесь .) Однако, поскольку поддержка браузером модулей ES6 изначально была плохой, люди начали использовать загрузчики модулей для объединения зависимостей в один кросс-браузерный файл, совместимый с ES5. Этот процесс представляет свои проблемы и степень сложности.
Но хорошие новости под рукой. Поддержка браузеров становится все лучше, поэтому давайте посмотрим, как вы можете использовать модули ES6 в современных браузерах.
Современный ландшафт ES-модулей
Safari, Chrome, Firefox и Edge поддерживают синтаксис импорта модулей ES6. Вот как они выглядят.
<script type="module"> import { tag } from './html.js' const h1 = tag('h1', ' Hello Modules!') document.body.appendChild(h1) </script>
// html.js export function tag (tag, text) { const el = document.createElement(tag) el.textContent = text return el }
Или как внешний скрипт:
<script type="module" src="app.js"></script>
// app.js import { tag } from './html.js' const h1 = tag('h1', ' Hello Modules!') document.body.appendChild(h1)
Просто добавьте type="module"
в теги скрипта, и браузер загрузит их как ES Modules. Браузер будет следовать всем путям импорта, загружая и выполняя каждый модуль только один раз.
Старые браузеры не будут выполнять сценарии с неизвестным «типом», но вы можете определить резервные сценарии с атрибутом nomodule
:
<script type="module" src="module.js"></script> <script nomodule src="fallback.js"></script>
Требования
Вам понадобится сервер, чтобы иметь возможность извлекать данные с помощью импорта, так как он не работает с протоколом file://
. Вы можете использовать npx serve
для запуска сервера в текущем каталоге для локального тестирования.
Если вы хотите загрузить модули ES в другой домен, вам нужно включить CORS
,
Если вы достаточно смелы, чтобы попробовать это сегодня, вы все равно должны будете создать отдельные пакеты для старых браузеров. В браузере es-module-loader имеется полифилл, который соответствует спецификации. Тем не менее, это не рекомендуется для производства вообще.
<script nomodule src="https://unpkg.com/browser-es-module-loader/dist/babel-browser-build.js"></script> <script nomodule src="https://unpkg.com/browser-es-module-loader"></script> <script type="module" src="./app.js"></script>
Производительность
Пока не выбрасывайте свои инструменты сборки, такие как Babel и Webpack, поскольку браузеры все еще реализуют способы оптимизации выборки. Тем не менее, в будущем с модулями ES будут иметь место ошибки и улучшения производительности.
Почему мы связываем
Сегодня мы связываем наш JavaScript, чтобы уменьшить количество HTTP-запросов, так как сеть часто является самой медленной частью загрузки веб-страницы. Это все еще очень актуальная проблема сегодня, но будущее блестящее: модули ES с поддержкой HTTP2 для потоковой передачи нескольких ресурсов с помощью push-серверов и браузеров, реализующих предварительную загрузку .
Предварительная загрузка
ссылка rel = ”modulepreload” скоро появится в ближайшем к вам браузере. Вместо того, чтобы браузер разрешал импорт всех модулей один за другим, создавая сетевой водопад, подобный этому…
<script type="module" src="./app.js"></script>
---> GET index.html <--- ---> GET app.js <--- ---> GET html.js <--- ---> GET lib.js <---
… Вы сможете html.js
сообщить браузеру, что на страницах требуются html.js
и lib.js
, что позволяет контролировать этот водопад:
<link rel="modulepreload" href="html.js"> <link rel="modulepreload" href="lib.js"> <script type="module" src="./app.js"></script>
---> GET /index.html <--- ---> GET app.js ---> GET html.js ---> GET lib.js <--- <--- <---
HTTP2 с сервером Push
HTTP2 способен выдвинуть несколько ресурсов в одном ответе по сравнению с HTTP1.1, который может доставить только один. Это поможет свести к минимуму количество поездок по сети.
В нашем примере было бы возможно доставить index.html
, app.js
и html.js
в одном запросе:
---> GET /index.html <--- index.html <--- app.js <--- html.js <--- lib.js
Кэширование
Предоставление нескольких меньших модулей ES может принести пользу кешированию, так как браузеру нужно будет выбирать только те, которые были изменены. Проблема с созданием больших пакетов заключается в том, что если вы измените одну строку, вы лишите законной силы весь пакет.
асинхронный / отложенный
По умолчанию модули ES не блокируют рендеринг, как <script defer>
. Если ваши модули не нужно выполнять в том же порядке, в котором они определены в HTML, вы также можете добавить async
выполнение для их выполнения, как только они будут загружены.
Библиотеки
Популярные библиотеки начинают публиковаться как модули ES, однако они все еще нацелены на сборщики, а не на прямой импорт.
Этот скромный небольшой импорт вызывает водопад из 640 запросов :
<script type="module"> import _ from 'https://unpkg.com/lodash-es' </script>
Как насчет того, чтобы сделать правильные вещи и импортировать только одну нужную нам функцию? Нам осталось всего 119 запросов :
<script type="module"> import cloneDeep from 'https://unpkg.com/lodash-es/cloneDeep' </script>
Это всего лишь пример, демонстрирующий, что lodash-es
еще не создан для загрузки непосредственно в браузер. Для этого вам все равно нужно будет создать собственный пакет с ES-модулями в качестве цели.
Поддержка браузера
Как показано в следующей таблице, поддержка браузером модулей ES хорошая (и постоянно улучшается).
Время начать экспериментировать с ES-модулями в браузере сейчас. Достаточно скоро вы сможете использовать их во всех современных браузерах без транспилятора или упаковщика, если хотите.