Загружаем babel-polyfill только для старых браузеров на примере vue.js
Это сервис, который на основании юзер-агента определяет какие полифиллы нужно загружать.
Попросту в index.html добавляем:
script src pl-s">https://cdn.polyfill.io/v2/polyfill.min.js?features=es6">script>
Правда тогда отдельные полифиллы будут загружаться даже для свежих версий хрома/фф. Решение — используем атрибут nomodule. Современные браузеры не будут загружать скрипт с этим атрибутом:
script src pl-s">https://cdn.polyfill.io/v2/polyfill.min.js?features=es6" nomodule>script>
Однако у polyfill.io есть и минусы: плохие полифиллы, не гарантирующие полную совместимость. По крайней мере так пишет автор core-js.
2. Поэтому загружаем babel-polyfill
Тоже используем nomodule , чтобы грузить только на старых браузерах:
script src pl-s">https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.26.0/polyfill.min.js" nomodule>script>
3. Альтернатива: как раньше импортируем babel-polyfill в коде
Но делаем как советуют в гайде по vue-cli.
module.exports = presets: [ ['@vue/app', "useBuiltIns": "entry" >] ], >;
В начало main.js добавляем (не забыв сделать npm install @babel/polyfill ):
import '@babel/polyfill';
В этом случае в бандл добавятся не все полифиллы, а только встречающиеся в коде и сооветствующие browserlist.
При этом сократить бандл для современных браузеров можно при помощи modern mode. Правда даже в этом случае часть полифиллов будет добавлена для современных браузеров. Возможно это особенность browserlist, а может и действительно они им нужны, не знаю.
Вопрос №48379 от пользователя Алексей Черняев в уроке «Полифиллы», курс «JS: DOM API»
Не понял, для чего используют core-js. Babel не является альтернативой?
Алексей Черняев, добрый день. Бабель — транспилятор. То есть, он только берет код и превращает его в тот, который вы от него просите. Полифиллы — непосредственно код, который добавляет новый функционал туда, где он не поддерживается. И бабель, начиная с 7 версии, не берет на себя задачу добавления полифилов. Он ими только пользуется, если они будут предоставлены. Поэтому надо использовать бабель и core-js в связке
Александр Фуфаев, кажется, я нашёл это замечание . То есть раньше Babel самостоятельно добавлял полифиллы через @babel/polyfill, а теперь нужен core-js?
Алексей Черняев, именно так. Более того babel/polyfill — просто оболочка вокруг core-js + runtime-generator
Предоставляйте современный код современным браузерам для более быстрой загрузки страниц.
Оптимизируйте свои подборки Сохраняйте и классифицируйте контент в соответствии со своими настройками.
Хусейн Джирде
Чтобы следовать этой кодовой лаборатории, откройте этот глюк на второй вкладке. Примечание. В этой лаборатории кода используются Chrome DevTools. Загрузите Chrome, если у вас его еще нет.
В этой лаборатории кода вы улучшите производительность простого приложения, которое позволяет пользователям оценивать случайных кошек. Узнайте, как оптимизировать пакет JavaScript, минимизировав объем передаваемого кода.

В примере приложения вы можете выбрать слово или смайлик, чтобы передать, насколько вам нравится каждый кот. Когда вы нажимаете кнопку, приложение отображает значение кнопки под текущим изображением кошки.
Мера
Примечание. Поскольку в этом приложении используется веб-пакет, любые изменения, внесенные в код, приведут к созданию новой сборки, которая может занять несколько секунд. После завершения вы увидите изменения, отраженные в приложении.
Всегда полезно начать с проверки веб-сайта, прежде чем добавлять какие-либо оптимизации:
- Чтобы просмотреть сайт, нажмите «Просмотреть приложение» . Затем нажмите Полноэкранный режим .
- Нажмите «Control+Shift+J» (или «Command+Option+J» на Mac), чтобы открыть DevTools.
- Откройте вкладку «Сеть» .
- Установите флажок Отключить кеш .
- Перезагрузите приложение.

Для этого приложения используется более 80 КБ! Пришло время узнать, не используются ли части пакета:
- Нажмите Control+Shift+P (или Command+Shift+P на Mac), чтобы открыть меню команд .

- Введите Show Coverage и нажмите Enter , чтобы отобразить вкладку «Покрытие» .
- На вкладке «Покрытие» нажмите «Обновить» , чтобы перезагрузить приложение во время сбора данных о покрытии.

- Посмотрите, сколько кода было использовано по сравнению с тем, сколько было загружено для основного пакета:

Более половины пакета (44 КБ) даже не используется. Это связано с тем, что большая часть кода состоит из полифилов, обеспечивающих работу приложения в старых браузерах.
Используйте @babel/preset-env
Синтаксис языка JavaScript соответствует стандарту, известному как ECMAScript или ECMA-262 . Новые версии спецификации выпускаются каждый год и включают новые функции, прошедшие процедуру предложения. Каждый основной браузер всегда находится на разном этапе поддержки этих функций.
В приложении используются следующие возможности ES2015:
- Стрелочные функции
- Литералы шаблонов
- Для… цикла
- Деструктуризация задания
Также используется следующая функция ES2017:
Не стесняйтесь погрузиться в исходный код в src/index.js , чтобы увидеть, как все это используется.
Все эти функции поддерживаются в последней версии Chrome, но как насчет других браузеров, которые их не поддерживают? Babel , включенная в приложение, — это самая популярная библиотека, используемая для компиляции кода, содержащего новый синтаксис, в код, понятный старым браузерам и средам. Это делается двумя способами:
- Полифиллы включены для эмуляции новых функций ES2015+, чтобы их API можно было использовать, даже если они не поддерживаются браузером. Вот пример полифила метода Array.includes .
- Плагины используются для преобразования кода ES2015 (или более поздней версии) в более старый синтаксис ES5. Поскольку это изменения, связанные с синтаксисом (например, функции стрелок), их нельзя эмулировать с помощью полифилов.
Посмотрите package.json чтобы узнать, какие библиотеки Babel включены:
"dependencies": < "@babel/polyfill": "^7.0.0" >, "devDependencies": < //. "babel-loader": "^8.0.2", "@babel/core": "^7.1.0", "@babel/preset-env": "^7.1.0", //. >
- @babel/core — основной компилятор Babel. При этом все конфигурации Babel определяются в .babelrc в корне проекта.
- babel-loader включает Babel в процесс сборки веб-пакета.
Теперь посмотрите на webpack.config.js , чтобы увидеть, как обычно включается babel-loader :
module: < rules: [ //. < test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" > ] >,
- @babel/polyfill предоставляет все необходимые полифилы для любых новых функций ECMAScript, чтобы они могли работать в средах, которые их не поддерживают. Он уже импортирован в самом верху src/index.js.
import "./style.css"; import "@babel/polyfill";
- @babel/preset-env определяет, какие преобразования и полифилы необходимы для любых браузеров или сред, выбранных в качестве целевых.
Взгляните на файл конфигурации Babel, .babelrc , чтобы узнать, как он включен:
Это установка Babel и веб-пакета. Узнайте, как включить Babel в свое приложение, если вы используете другой сборщик модулей, чем веб-пакет.
Атрибут targets в .babelrc определяет, какие браузеры являются мишенью. @babel/preset-env интегрируется со списком браузеров, а это значит, что вы можете найти полный список совместимых запросов, которые можно использовать в этом поле, в документации по списку браузеров .
Значение «last 2 versions» транспилирует код в приложении для двух последних версий каждого браузера.
Отладка
Чтобы получить полное представление обо всех целях Babel браузера, а также обо всех включенных преобразованиях и полифилах, добавьте поле debug в .babelrc:
Перезагрузите приложение и просмотрите журналы состояния сбоев в нижней части редактора.
Целевые браузеры
Babel записывает в консоль ряд подробностей о процессе компиляции, включая все целевые среды, для которых был скомпилирован код.

Обратите внимание, что в этот список включены браузеры, выпуск которых прекращен, например Internet Explorer. Это проблема, поскольку в неподдерживаемые браузеры не будут добавлены новые функции, и Babel продолжает переносить для них определенный синтаксис. Это неоправданно увеличивает размер вашего пакета, если пользователи не используют этот браузер для доступа к вашему сайту.
Babel также записывает список используемых плагинов преобразования:

Это довольно длинный список! Это все плагины, которые необходимо использовать Babel для преобразования любого синтаксиса ES2015+ в более старый синтаксис для всех целевых браузеров.
Однако Babel не показывает какие-либо конкретные используемые полифилы:
![]()
Это связано с тем, что весь @babel/polyfill импортируется напрямую.
Загружать полифилы по отдельности
По умолчанию Babel включает все полифилы, необходимые для полной среды ES2015+, когда @babel/polyfill импортируется в файл. Чтобы импортировать определенные полифилы, необходимые для целевых браузеров, добавьте в конфигурацию запись useBuiltIns: ‘entry’ .
Перезагрузите приложение. Теперь вы можете увидеть все включенные в него полифилы:
Хотя теперь включены только необходимые полифилы для «last 2 versions» , это по-прежнему очень длинный список! Это связано с тем, что полифилы, необходимые целевым браузерам для каждой новой функции, по-прежнему включены. Измените значение атрибута на usage , чтобы включать только те функции, которые используются в коде.
При этом полифилы автоматически включаются там, где это необходимо. Это означает, что вы можете удалить импорт @babel/polyfill в src/index.js.
import "./style.css"; import "@babel/polyfill";
Теперь включены только необходимые для приложения полифилы.

Размер пакета приложений значительно уменьшен.

Сужение списка поддерживаемых браузеров
Число включенных целевых браузеров по-прежнему довольно велико, и немногие пользователи используют устаревшие браузеры, такие как Internet Explorer. Обновите конфигурации до следующего:
< "presets": [ [ "@babel/preset-env", < "targets": "last 2 versions", "targets": [">0.25%", "not ie 11"], "debug": true, "useBuiltIns": "usage", > ] ] >
Взгляните на детали полученного комплекта.

Поскольку приложение настолько маленькое, эти изменения на самом деле не имеют большой разницы. Однако рекомендуется использовать процентную долю рынка браузеров (например, «>0.25%» и исключать определенные браузеры, которые, как вы уверены, не используют ваши пользователи. Чтобы узнать больше об этом, прочтите статью Джеймса Кайла «Последние 2 версии», которую считают вредной .
Используйте
Есть еще много возможностей для улучшения. Хотя ряд неиспользуемых полифилов был удален, многие из них уже поставляются и не нужны для некоторых браузеров. Используя модули, можно писать новый синтаксис и отправлять его в браузеры напрямую без использования ненужных полифилов.
Модули JavaScript — относительно новая функция, поддерживаемая во всех основных браузерах . Модули можно создавать с использованием атрибута type=»module» для определения сценариев, которые импортируют и экспортируют из других модулей. Например:
// math.mjs export const add = (x, y) => x + y;
Многие новые функции ECMAScript уже поддерживаются в средах, поддерживающих модули JavaScript (вместо Babel). Это означает, что конфигурацию Babel можно изменить для отправки в браузер двух разных версий вашего приложения:
- Версия, которая будет работать в новых браузерах, поддерживающих модули и включающая модуль, который практически не транспилируется, но имеет меньший размер файла.
- Версия, включающая более крупный транспилированный скрипт, который будет работать в любом устаревшем браузере.
Использование модулей ES с Babel
Чтобы иметь отдельные настройки @babel/preset-env для двух версий приложения, удалите файл .babelrc . Настройки Babel можно добавить в конфигурацию веб-пакета, указав два разных формата компиляции для каждой версии приложения.
Начните с добавления конфигурации устаревшего скрипта в webpack.config.js :
const legacyConfig = < entry, output: < path: path.resolve(__dirname, "public"), filename: "[name].bundle.js" >, module: < rules: [ < test: /\.js$/, exclude: /node_modules/, loader: "babel-loader", options: < presets: [ ["@babel/preset-env", < useBuiltIns: "usage", targets: < esmodules: false >>] ] > >, cssRule ] >, plugins >
Обратите внимание, что вместо использования targets значения для «@babel/preset-env» вместо этого используются esmodules со значением false . Это означает, что Babel включает в себя все необходимые преобразования и полифилы для каждого браузера, который еще не поддерживает модули ES.
Добавьте объекты entry , cssRule и corePlugins в начало файла webpack.config.js . Все они используются как модулем, так и устаревшими сценариями, передаваемыми в браузер.
const entry = < main: "./src" >; const cssRule = < test: /\.css$/, use: ExtractTextPlugin.extract(< fallback: "style-loader", use: "css-loader" >) >; const plugins = [ new ExtractTextPlugin(), new HtmlWebpackPlugin() ];
Теперь аналогичным образом создайте объект конфигурации для сценария модуля ниже, где определен legacyConfig :
const moduleConfig = < entry, output: < path: path.resolve(__dirname, "public"), filename: "[name].mjs" >, module: < rules: [ < test: /\.js$/, exclude: /node_modules/, loader: "babel-loader", options: < presets: [ ["@babel/preset-env", < useBuiltIns: "usage", targets: < esmodules: true >>] ] > >, cssRule ] >, plugins >
Основное отличие здесь заключается в том, что для имени выходного файла используется расширение .mjs . Здесь для значения esmodules установлено значение true, что означает, что код, выводимый в этот модуль, представляет собой меньший по размеру и менее компилируемый сценарий, который не подвергается каким-либо преобразованиям в этом примере, поскольку все используемые функции уже поддерживаются в браузерах, поддерживающих модули.
В самом конце файла экспортируйте обе конфигурации в один массив.
module.exports = [ legacyConfig, moduleConfig ];
Теперь создается как меньший модуль для браузеров, которые его поддерживают, так и более крупный транспилированный скрипт для старых браузеров.
Браузеры, поддерживающие модули, игнорируют скрипты с атрибутом nomodule . И наоборот, браузеры, которые не поддерживают модули, игнорируют элементы сценария с type=»module» . Это означает, что вы можете включить как модуль, так и скомпилированный резервный вариант. В идеале две версии приложения должны находиться в index.html следующим образом:
Браузеры, поддерживающие модули, извлекают и выполняют main.mjs и игнорируют main.bundle.js. Браузеры, не поддерживающие модули, делают наоборот.
Важно отметить, что в отличие от обычных скриптов, скрипты модулей по умолчанию всегда откладываются. Если вы хотите, чтобы эквивалентный скрипт nomodule также откладывался и выполнялся только после синтаксического анализа, вам необходимо добавить атрибут defer :
Последнее, что здесь нужно сделать, — это добавить атрибуты module и nomodule к модулю и устаревшему скрипту соответственно. Импортируйте ScriptExtHtmlWebpackPlugin в самый верх webpack.config.js :
const path = require("path"); const webpack = require("webpack"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const ScriptExtHtmlWebpackPlugin = require("script-ext-html-webpack-plugin");
Теперь обновите массив plugins в конфигурациях, чтобы включить этот плагин:
const plugins = [ new ExtractTextPlugin(), new HtmlWebpackPlugin(), new ScriptExtHtmlWebpackPlugin(< module: /\.mjs$/, custom: [ < test: /\.js$/, attribute: 'nomodule', value: '' >, ] >) ];
Эти настройки плагина добавляют атрибут type=»module» для всех элементов сценария .mjs , а также атрибут nomodule для всех модулей сценария .js .
Примечание. Если у вас возникли проблемы с пониманием того, как добавить все эти конфигурации в webpack.config.js , взгляните на полную версию файла .
Обслуживание модулей в HTML-документе
Последнее, что нужно сделать, — это вывести как устаревшие, так и современные элементы сценария в HTML-файл. К сожалению, плагин HTMLWebpackPlugin , создающий окончательный HTML-файл, в настоящее время не поддерживает вывод скриптов модуля и nomodule. Хотя для решения этой проблемы существуют обходные пути и отдельные плагины, такие как BabelMultiTargetPlugin и HTMLWebpackMultiBuildPlugin , для целей данного руководства используется более простой подход — добавление элемента сценария модуля вручную.
Добавьте следующее в src/index.js в конце файла:
Теперь загрузите приложение в браузере, поддерживающем модули, например в последней версии Chrome.

Извлекается только модуль с гораздо меньшим размером пакета, поскольку он практически не транспилируется! Другой элемент сценария полностью игнорируется браузером.
Если вы загружаете приложение в более старом браузере, будет загружен только более крупный транспилированный скрипт со всеми необходимыми полифилами и преобразованиями. Вот скриншот всех запросов, сделанных в более старой версии Chrome (версия 38).

Заключение
Теперь вы понимаете, как использовать @babel/preset-env для предоставления только необходимых полифилов, необходимых для целевых браузеров. Вы также знаете, как модули JavaScript могут еще больше повысить производительность, предоставляя две разные транспилированные версии приложения. Имея хорошее представление о том, как оба эти метода могут значительно сократить размер вашего пакета, приступайте к оптимизации!
Если не указано иное, контент на этой странице предоставляется по лицензии Creative Commons «С указанием авторства 4.0», а примеры кода – по лицензии Apache 2.0. Подробнее об этом написано в правилах сайта. Java – это зарегистрированный товарный знак корпорации Oracle и ее аффилированных лиц.
Последнее обновление: 2018-12-12 UTC.
Оптимизация кода под старые браузеры
В package.json нужно добавить после «license»: «ISC» :
"license": "ISC", "browserslist": [ ">1%" ],
В файл webpack.config.js необходимо добавить в раздел module :
rules: [ test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: loader: 'babel-loader', options: presets: [['@babel/preset-env', debug: true, corejs: 3, useBuiltIns: "usage" >]] > > > ]
test – регулярное выражение для поиска файлов которые необходимо перобразовать
corejs – сообщяем о необходимости библиотеки corejs. useBuiltIns: «usage» — Проверяем имеющийся код и загружаем только те библиотеки, которые необходимы (а не все что есть).
npm i --save-dev babel-loader npm i --save-dev core-js