На этот раз я подробно расскажу о babel (акцент на приложении), если есть какие-либо ошибки, пожалуйста, укажите
что такое бабель?
Развитие браузеров никогда не поспевает за развитием языков, хотя es6+ очень популярен, не все браузеры могут поддерживать синтаксис es6+. Рождение Вавилона проистекает из этого.
Официальное определение:
Babel — это цепочка инструментов, в основном используемая для преобразования кода версии ECMAScript 2015+ в обратно совместимый синтаксис JavaScript, чтобы его можно было запускать в текущих и более старых браузерах или других средах.
об имени Бабель
перевел БабельВавилонская башнятакже переводится какВавилонская башня,Башня Вавилона, или перефразируя какВавилонская башня), которыйиудаизм"Танах·Бытие(также известная как Еврейская Библия или Ветхий Завет) история:
Далее выдержка изВикипедия
Бытие, глава 11, стихи 1-9, описывает историю «города Вавилона». Люди на земле говорили в то время на одном языке, и когда люди ушли с востока, они пришли в землю Сеннаар.Там люди находят способы сжигать кирпичи, чтобы построить город и высокую башню, чтобы распространить свое имя.,чтобы они не рассеялись по всему миру. После того, как Бог пришел в мир, он увидел этот город и эту башню,Нет ничего, что они не могли бы сделать с группой людей, говорящих только на одном языке.; поэтому Бог смешал их языки, чтобы они не могли понять, что говорят другие, и рассеял их по всему миру, и город перестал строиться. Город называется «Вавилонский город», а башня называется «Вавилонская башня».
Угадайте, что имя Вавилон может быть связано с этим: оно символизирует, что люди говорят на одном языке и работают вместе, чтобы соперничать с богом небес.
Как работает Бабель
Babel это транспайлер.По сравнению с компилятором правильнее называть транслятор транспайлером,потому что он всего лишь переводит правила старшей версии того же языка в правила младшей версии,в отличие от компилятора,выход другой , Код языка более низкого уровня.
Но, подобно компилятору, процесс перевода Babel также делится на три этапа:разбор, преобразование, генерация, взяв в качестве примера перевод кода ES6 в код ES5, конкретный процесс перевода babel выглядит следующим образом:
Ввод кода ES6 ==" babylon для синтаксического анализа ==" для получения AST
==" Плагин использует babel-traverse для обхода и преобразования дерева AST ==" Получить новое дерево AST
==" Используйте Babel-генератор для генерации кода ES5 через дерево AST
Для получения более подробной информации глубокого изучения нет. Кому интересно, можете обратиться к этой статье»Анатомия Вавилона - Обзор Вавилона》
Использование babel в проекте (выделено)
Три основных фреймворка, используемых в настоящее время, имеют соответствующие вспомогательные инструменты, которые тесно помогли нам интегрировать различные конфигурации Babel, поэтому нет необходимости учиться. Расстояние между тобой и здоровяком может быть как одна обучающая вавилона~
Далее давайте подробнее рассмотрим конфигурацию babel, чтобы вы больше не путались, увидев эти конфигурации.
Посылка теоретических знаний
Babel делит es6+ (имеется в виду es6 и выше) на
- Уровень синтаксиса: let, const, class, функция стрелки и т. д. Они должны быть переведены во время построения, что относится к переводу на уровне синтаксиса (например,
class...
будет переведено наvar function...
) - Слой API: Promise, include, map и т. д. Это новые методы прототипа global или Object, Array и т. д. Они могут быть переопределены соответствующими методами es5.
Бабелевский перевод этих двух категорий определенно отличается, и нам также нужно дать соответствующую конфигурацию
Установить
Знание базовой теории только после. Тогда вы действительно можете использовать babel.
Прежде чем использовать babel, вы должны сначала установить соответствующие зависимости. Требуемый минимум:
- babel-core: ядро Babel, включая API каждого ядра, используемое плагинами Babel и инструментами упаковки.
- babel-cli: инструмент командной строки для экранирования js-файлов
npm install --save-dev @babel/core @babel/cli
инициализация тестового проекта
Чтобы более понятно объяснить babel, мы можем сначала создать тестовый проект.
Сначала создайте папку babel-study, выполнитеnpm init -y
для инициализации. Создайте проект src/index.js и напишите следующий код es6:
let a = 1
let b = 2
let c = a+b
Примечание:Вот только пусть принадлежит es6, и только синтаксически. Давайте сначала посмотрим на уровень синтаксиса, начиная с самого простого, а затем на уровень API
Добавьте команду --compiler в package.json для выполнения babel
//..."scripts": { "compiler": "babel src --out-dir lib --watch"}
затем выполнить npm run compiler
Теоретически babel преобразует let в var, но вы обнаружите, что код, переведенный на данный момент, такой же, как и исходный, почему так?
Сам Babel не имеет никакой функции преобразования, он разбивает функции преобразования на плагины один за другим. Поэтому, когда мы не настраиваем никаких плагинов, код и входные данные, проходящие через Babel, остаются теми же.
Итак, нам нужно установить плагин
Плагины (для обработки слоев синтаксиса)
Существует два способа использования плагинов: один — устанавливать их один за другим (более хлопотно), а другой — устанавливать группу плагинов предустановленным образом.Конечно, мы должны выбрать пресет, который спасает от неприятностей.
- Первая установка предустановки
npm i @babel/preset-env -D
Плагины, включенные @babel/preset-env, будут поддерживать все последние функции JS (ES2015, ES2016 и т. д., за исключением стадии). - Конфигурация:
Создайте файл .babelrc или файл babelconfig.js, добавьте следующий код, Babel автоматически найдет этот файл
//.babelrc
{
"presets": ["@babel/preset-env"]
}
Дополнительные инструкции: Если вы используете Vue, пресеты обычно @vue/app, это добавляет множество самоопределяемых плагинов к плагинам, включенным в @babel/preset-env.
Все приложения Vue CLI используют @vue/babel-preset-app, который включает в себя babel-preset-env, поддержку JSX и конфигурацию, оптимизированную для минимального размера пакета. Более подробную информацию и предустановленные параметры можно найти в его документации. --- Выдержки из официальной документации vue-cli
Судя по документации, @vue/babel-preset-app по умолчанию настроен с @babel/plugin-transform-runtime.
Выполните команду, на данный момент перевод выполнен успешно, и результаты перевода следующие:
"use strict";
var a = 1;
var b = 2;
var c = a + b;
- целевой атрибут
Babel также может настроить taget или предоставить файл .browserlist, чтобы указать целевую среду, что может уменьшить размер вашего кода.
//.browserslistrc
> 0.25%
not dead
polyfill (для обработки слоя API)
Вышеупомянутое только проверяет перевод на грамматическом уровне.Далее, давайте попробуем перевод на уровне API.
Мы модифицируем index.js следующим образом:
// Promise是api层面的,是一个es6中的全局对象
const p = new Promise((resolve, reject) => {
resolve(100);
});
Выполните команду компилятора, и результат компиляции будет следующим:
"use strict";
var p = new Promise(function (resolve, reject) {
resolve(100);
});
const-->var — это нормально, но Promise ничего не меняет, что определенно неправильно.
тогда нужноPolyfillэта вещь.
polyfillКитайское значение shim, как следует из названия, заключается в сглаживании различий между разными браузерами или разными средами, чтобы новые встроенные функции, методы экземпляров и т. д. также можно было использовать в браузерах более ранних версий.
как использовать:
Сначала установите@babel/polyfill
полагаться. Обратите внимание, что это зависимость времени выполнения. Так что не добавляйте -devnpm install --save @babel/polyfill
@babel/polyfill
модуль включаетcore-js
и обычайregenerator runtime
Модуль, имитирующий полную среду ES2015+.
Затем импортируйте его в index.js
import '@babel/polyfill';
const p = new Promise((resolve, reject) => {
resolve(100);
});
Результат перевода:
"use strict";
require("@babel/polyfill");
var p = new Promise(function (resolve, reject) {
resolve(100);
});
Хотя кажется, что Promise все еще не переведен, представленный нами полифилл уже содержит определение es5 Promise, так что в настоящее время код можно запустить в браузерах более ранних версий.
использованиеBuiltInsproperty
Я не знаю, если вы не думали о такой проблеме Я использую только несколько es6 в своем коде, но мне нужно ввести все прокладки, что неразумно. Чтобы оптимизировать это, вам нужно использовать свойство useBuiltIns.useBuiltIns
Этот элемент конфигурации имеет три значения:
-
false
: не правильноpolyfills
Делать что-нибудь -
entry
: согласно сtarget
В браузерной версии поддержка будетpolyfills
Разделить введение, ввести только те, которые не поддерживаются браузерамиpolyfill
-
usage(新)
: в коде обнаруженияES6/7/8
и т. д., загружайте только те, которые используются в кодеpolyfills
Затем мы модифицируем конфигурацию следующим образом:
//.babelrc
{
"presets": [
["@babel/preset-env",{
"useBuiltIns": "usage"
}]
]
}
Выполните команду компилятора, которая является предупреждением в командной строке.
Это означает, что нам нужно указать версию corejs. Затем мы можем указать его, и способ указания также очень прост:
{
"presets": [
["@babel/preset-env",{
"useBuiltIns": "usage",
"corejs":3
}]
]
}
В настоящее время рекомендуемой версией corejs является версия 3, и новые функции будут добавлены только в этой версии.
На данный момент результат перевода выглядит следующим образом:
"use strict";
require("core-js/modules/es.object.to-string");
require("core-js/modules/es.promise");
var p = new Promise(function (resolve, reject) {
resolve(100);
});
Пока вроде всё идеально!
Тем не менее, мы — одна @babel/plugin-transform-runtime от совершенства.
@babel/plugin-transform-runtime
Устранение избыточности кода
Избыточность кода — проблема, возникающая на уровне синтаксиса перевода.
Прежде всего, мы все еще модифицируем наш index.js, На этот раз мы напишем es6--> class уровня грамматики (пусть, const не проблема, поэтому используйте класс), чтобы увидеть, во что Babel преобразует class в
//index.js
class Student {
constructor(name,age){
this.name = name;
this.age = age
}
}
Результаты конвертации
"use strict";
require("core-js/modules/es.function.name");
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Student = function Student(name, age) {
_classCallCheck(this, Student);
this.name = name;
this.age = age;
};
Этот результат не кажется неправильным, но на самом деле, если мы используем класс в других файлах, вы обнаружите, что _classCallCheck будет появляться в каждом файле, что создает избыточность кода (в нашем примере используется только класс, может быть избыточным и не очевидным). , и эти функции могут быть очень длинными в реальных проектах).
Теперь вам нужен другой плагин@babel/plugin-transform-runtime
.
Этот подключаемый модуль позволит повторно использовать вспомогательные функции, внедренные Babel (такие как _classCallCheck выше), для уменьшения размера кода.Эти вспомогательные функции находятся в@babel/runtime
, поэтому вам нужно установить@babel/runtime
, и, конечно же, @babel/runtime также является зависимостью времени выполнения. (Babel необходимо использовать некоторые вспомогательные функции при компиляции некоторых грамматик)
Установить@babel/plugin-transform-runtime
а также@babel/runtime
npm i --save-dev @babel/plugin-transform-runtime @babel/runtime
Затем измените конфигурацию
{
"presets": [
["@babel/preset-env",{
"useBuiltIns":"usage",
"corejs":3
}]
],
"plugins": [
["@babel/plugin-transform-runtime"]
]
}
скомпилировать результат
"use strict";
require("core-js/modules/es.function.name");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var Student = function Student(name, age) {
(0, _classCallCheck2["default"])(this, Student);
this.name = name;
this.age = age;
};
Можно обнаружить, что связанные вспомогательные функции вводятся в виде require, а не вставляются напрямую, поэтому они не будут избыточными.
Помимо решения проблемы избыточности кода, у @babel/plugin-transform-runtime есть еще одна важная способность — решение проблемы глобального загрязнения.
Решить глобальное загрязнение
Глобальное загрязнение — это проблема, возникающая на уровне API трансляции.
На этот раз мы по-прежнему используем обещания для экспериментов.
Изменить index.js
new Promise(function (resolve, reject) {
resolve(100);
});
Результаты перевода
"use strict";
require("core-js/modules/es.object.to-string");
require("core-js/modules/es.promise");
new Promise(function (resolve, reject) {
resolve(100);
});
Видно, что когда preset-env обрабатывает такие API, как Promise, он вводит только соответствующие js-библиотеки в core-js, которые переопределяют Promise и монтируют его глобально.
Проблема здесь в том, что это неизбежно вызовет загрязнение глобальных переменных.Также другие, такие как Array.from, изменят прототипы этих глобальных объектов, что также вызовет загрязнение глобальных объектов.
Решение состоит в том, чтобы передать core-js среде времени выполнения для обработки. Просто добавьте конфигурацию, очень просто
{
"presets": [
["@babel/preset-env"]
],
"plugins": [
["@babel/plugin-transform-runtime",{
"corejs":3
}]
]
}
Видно, что мы добавляем атрибут core-js в@babel/plugin-transform-runtime
В конфигурации этого плагина пусть этот плагин обрабатывает это, и нет необходимости настраивать useBuiltIns, потому что он был установлен как значение по умолчанию в babel7.
(transform-runtime использует плагин для автоматического определения и замены новых функций в коде и использования того, что необходимо)
Обратите внимание: в некоторых блогах говорится, что такие методы экземпляра, как include, не могут быть переведены. На самом деле это неправильно. В официальной документации сказано следующее:corejs: 2
Поддерживаются только глобальные переменные (например,Promise
) и статические свойства, такие какArray.from
),corejs: 3
Также поддерживаются свойства экземпляра (например,[].includes
).
Результат перевода:
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _promise = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/promise"));
new _promise["default"](function (resolve, reject) {
resolve(100);
});
Видно, что код на данный момент не добавляет глобально Promse напрямую, а определяет метод _promise["default"], чтобы не было загрязнения глобальных переменных.
Таким образом, можно сделать вывод, что@babel/plugin-transform-runtime
Сила этого плагина заключается в следующем:
- Реализовать повторное использование вспомогательных функций и решить проблему избыточности кода, возникающую при переводе синтаксического слоя.
- Решите загрязнение глобальной переменной в API-слое перевода.
Но у transform-runtime есть и недостатки:
- Каждая функция обнаруживается и заменяется, что может привести к неэффективному переводу по мере роста приложения.
Дополнительные сведения о настройке этого плагина см.официальная документация
Использование babel в веб-пакете
Сначала установите babel-loader
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
"plugins": [
["@babel/plugin-transform-runtime",{
"corejs":3
}]
]
}
}
}
]
}
Студенты, использующие vue-cli, должны обратить внимание
Поскольку babel-loader медленный, webpack официально рекомендует транспилировать как можно меньше файлов (Ссылаться на), поэтому vue-cli настраивает параметр exclude загрузчика, чтобы исключить файлы в node_moduls, но это может вызвать проблемы совместимости для зависимости. Итак, если у вас есть проблемы совместимости с зависимостью в вашем проекте, это может быть причиной. Решение заключается в настройке в vue.config.jstranspileDependenciesС этой опцией Babel явно транслирует эту зависимость.
Ссылаться на
Благодаря следующим блоггерам
«Знания Babel7, которые нельзя упустить»
"Вавилонская китайская сеть"
"Вавилонская обучающая серия"
«Понимание Вавилона на (длинном) дыхании»
"Блог Wind Stone - babel"