Эта статья была впервые опубликована в публичном аккаунте vivo Internet Technology WeChat.
Связь:Tickets.WeChat.QQ.com/Yes/PL Еврей HUD0…
Добавить Автора
Введение
В предыдущем разделе "CommonJS: не интерфейс, но революционный интерфейс", мы говорили о модуле ES6, который является спецификацией для модулей в ES6. ES6 - это аббревиатура ECMAScript 6.0, которая обычно относится к стандарту языка JavaScript следующего поколения. Его первая версия, ES2015, была официально выпущена в июне. 2015. ES6, упомянутый в этой статье, включает ES2015, ES2016, ES2017 и т. д. В первом разделе «Веб: все время вперед и до конца, чтобы забыть реку» также упоминалось, что от разработки до выпуска ES2015 прошло более десяти лет, было добавлено множество новых функций и новых механизмов. введена, и поддержка ES6 в браузерах прогрессирует.Это далеко от энтузиазма разработчиков интерфейса использовать ES6, поэтому противоречие становится все более и более очевидным...
2. Что такое Вавилон
Давайте посмотрим на этоОфициальный сайтОпределение на:
Babel is a JavaScript compiler
Правильно, Babel — это компилятор для JavaScript. Что касается компилятора, вы можете обратиться кthe-super-tiny-compilerХорошие ответы можно найти в этом проекте.
Эта статья основана на версии Babel 7.9.0 для демонстрации и объяснения.Кроме того, учащимся рекомендуется прочитать официальный веб-сайт на английском языке.Официальный веб-сайт на китайском языке будет более медленной версией, чем исходный веб-сайт, и многие из них все еще находятся в стадии разработки. Английский.
Babel — это решение для преобразования кода ES6 в код, поддерживаемый браузерами или другими средами.Обратите внимание на мои слова, я не говорю о переходе на ES5, потому что разные типы и версии браузеров имеют разную степень поддержки новых функций ES6.Babel не может конвертировать те части, которые браузеры уже поддерживают, поэтому Babel будет зависеть от браузерная версия, о которой речь пойдет позже. Здесь вы можете обратиться кbrowerslistпроект.
История Вавилона
Прежде чем изучать какое-либо знание, я привык сначала понять его историю, чтобы я мог глубоко понять его смысл.
Babel написан инженером FaceBook Себастьяном Маккензи. В 2014 году он выпустил 6to5, компилятор для JavaScript. Как видно из названия, его основная функция — конвертировать ES6 в ES5.
ES6 здесь относится к ES2015, потому что он не был официально выпущен в то время, и название ES2015 официально не определено.
Поэтому многие люди отмечали, что 6to5 — это просто план перехода до поддержки ES6.Его авторы категорически не согласны с этой точкой зрения.Они считают, что 6to5 не только будет постепенно улучшаться в соответствии со стандартом, но и имеет очень большой потенциал для влиять и продвигать формулировку стандарта. Из-за этого команда 6to5 посчитала, что название «6to5» не совсем точно передает цели проекта. Кроме того, после официального выпуска ES6 он был назван ES2015, что отличается от его первоначального предназначения для 6to5. Итак, 15 февраля 2015 года 6to5 официально сменила название на Babel.
(картинка взята из интернета)
Вавилон — это Вавилонская башня в вавилонской культуре, так удачно названная 6to5! Я завидую этим офигенным людям.Они не только хорошо пишут,но и такие грамотные.Нам в отличие от нас приходится долго придерживать имя переменной,и страдать от бескультурья. Вот почему я назвал эту статью «Вавилон: Вавилон, который поднимает ES6 в небо».
3. Как пользоваться Бабелем
После понимания того, что такое Babel, очевидно, что нам нужно начать думать о том, как использовать Babel для преобразования кода ES 6. В дополнение к таким инструментам, как cli, предоставляемым самим Babel, он также поддерживает использование других инструментов упаковки, таких как webpack, rollup и т. д., вы можете обратиться кНа официальном сайте представлены инструкции по настройке для разных платформ..
Чтобы прочувствовать самое примитивное использование Babel, в этой статье для демонстрации используется cli Babel напрямую без каких-либо других инструментов.
1. Создайте демонстрационный проект Babel
Используйте следующую команду, чтобы собрать пакет npm и создать новый каталог src и файл index.js.
npm init -yСодержимое package.json следующее:
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}2. Установите пакеты зависимостей
npm install --save-dev @babel/core @babel/cli @babel/preset-envФункции этих пакетов будут представлены позже, давайте сначала рассмотрим их использование.
Добавьте команду babel для компиляции файлов из каталога src в каталог dist:
{
"name": "demo",
"version": "1.0.0",
"description": "",
"main": "src/index.js",
"scripts": {
"babel": "babel src --out-dir dist",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.0"
}
}3. Добавьте файл конфигурации Babel
Добавьте файл babel.config.js в корневой каталог проекта и добавьте конфигурацию компиляции Babel, если конфигурации нет, то она не будет скомпилирована.
const presets = [
[
'@babel/env',
{
debug: true
}
]
]
const plugins = []
module.exports = { presets, plugins }Конфигурация отладки в приведенном выше примере заключается в том, чтобы распечатать журналы, когда Babel работает Удобно посмотреть, какой синтаксис преобразовал Babel.
- Пресеты в основном предназначены для настройки пресетов, используемых для компиляции, а плагины в основном предназначены для настройки плагинов для завершения компиляции Конкретное значение будет обсуждаться позже.
- Рекомендуется использовать файлы Javascript для записи файлов конфигурации вместо файлов JSON, чтобы используемые пресеты и плагины можно было динамически настраивать в соответствии со средой.
const presets = [
[
'@babel/env',
{
debug: true
}
]
]
const plugins = []
if (process.env["ENV"] === "prod") {
plugins.push(...)
}
module.exports = { presets, plugins }4, скомпилировать результаты
После настройки мы запускаем команду npm run babel и видим, что файл index.js сгенерирован в папке dist и имеет следующее содержимое:
// src/index.js
const add = (a, b) => a + b
// dist/index.js
"use strict";
var add = function add(a, b) {
return a + b;
};Как видите, const ES6 преобразуется в var, а стрелочные функции — в обычные функции. При этом печатаются следующие журналы:
> babel src --out-dir dist
@babel/preset-env: `DEBUG` option
Using targets:
{}
Using modules transform: auto
Using plugins:
proposal-nullish-coalescing-operator {}
proposal-optional-chaining {}
proposal-json-strings {}
proposal-optional-catch-binding {}
transform-parameters {}
proposal-async-generator-functions {}
proposal-object-rest-spread {}
transform-dotall-regex {}
proposal-unicode-property-regex {}
transform-named-capturing-groups-regex {}
transform-async-to-generator {}
transform-exponentiation-operator {}
transform-template-literals {}
transform-literals {}
transform-function-name {}
transform-arrow-functions {}
transform-block-scoped-functions {}
transform-classes {}
transform-object-super {}
transform-shorthand-properties {}
transform-duplicate-keys {}
transform-computed-properties {}
transform-for-of {}
transform-sticky-regex {}
transform-unicode-regex {}
transform-spread {}
transform-destructuring {}
transform-block-scoping {}
transform-typeof-symbol {}
transform-new-target {}
transform-regenerator {}
transform-member-expression-literals {}
transform-property-literals {}
transform-reserved-words {}
transform-modules-commonjs {}
proposal-dynamic-import {}
Using polyfills: No polyfills were added, since the `useBuiltIns` option was not set.
Successfully compiled 1 file with Babel.В-четвертых, принцип работы Babel
Поняв, как его использовать, давайте изучим вещи, лежащие в основе компиляции, и познакомимся с композицией и расширенным использованием Babel.
1. Вавилонский рабочий процесс
Как упоминалось ранее, Babel на самом деле является чистым компилятором JavaScript. Рабочий процесс любого компилятора можно условно разделить на следующие три шага:
Парсер анализирует исходные файлы
Преобразование трансформации
Генератор генерирует новые файлы
Babel не является исключением, как показано на изображении ниже:
(картинка взята из интернета)
Поскольку Babel используетacornЭтот движок выполняет синтаксический анализ, и библиотека сначала преобразует исходный код вАбстрактное синтаксическое дерево (AST), затем преобразуйте AST и, наконец, выведите преобразованный AST, чтобы получить файл, скомпилированный Babel.
Так откуда Babel знает, как конвертировать? Ответ — через подключаемые модули. Babel предоставляет подключаемый модуль для каждого нового синтаксиса. Какие подключаемые модули настроены в конфигурации Babel, они будут преобразовывать соответствующий синтаксис подключаемого модуля. Плагины именуются в формате @babel/plugin-xxx.
2, Вавилонская композиция
(1) @babel/preset-env
Как упоминалось выше, @babel/preset-* на самом деле является набором плагинов для конвертации. журнал. . Если в исходном коде используется синтаксис, которого нет в @babel/preset-env, будет сообщено об ошибке, и вы сможете вручную добавить его в плагинах.
Например, ES6 четко оговаривает, что внутри класса есть только статические методы и никаких статических свойств. Но теперь есть предложение предоставлять статические свойства классов, которое записывается добавлением ключевого слова static перед свойствами экземпляра.
// src/index.js
const add = (a, b) => a + b
class Person {
static a = 'a';
static b;
name = 'morrain';
age = 18
}
В соответствии с сообщением об ошибке добавьте @babel/plugin-proposal-class-properties.
npm install --save-dev @babel/plugin-proposal-class-properties// babel.config.js
const presets = [
[
'@babel/env',
{
debug: true
}
]
]
const plugins = ['@babel/plugin-proposal-class-properties']
module.exports = { presets, plugins }
// src/index.js
const add = (a, b) => a + b
// dist/index.js 没有配置targets
"use strict";
var add = function add(a, b) {
return a + b;
};
// babel.config.js
const presets = [
[
'@babel/env',
{
debug: true,
targets: {
chrome: '58'
}
}
]
]
const plugins = ['@babel/plugin-proposal-class-properties']
module.exports = { presets, plugins }
// src/index.js
const add = (a, b) => a + b
// dist/index.js 配置targets chrome 58
"use strict";
const add = (a, b) => a + b;
Для удобства последующих поясненийtargetsКонфигурация удалена, чтобы позволить Babel транспилировать все грамматики по умолчанию.
(2) @бабель/полифилл
Дословный перевод слова «полифилл» означает «прокладка», и это очень важная концепция в Babel. Посмотрите на следующие строки кода:
// src/index.js
const add = (a, b) => a + b
const arr = [1, 2]
const hasThreee = arr.includes(3)
new Promise()
// dist/index.js
"use strict";
var add = function add(a, b) {
return a + b;
};
var arr = [1, 2];
var hasThreee = arr.includes(3);
new Promise();
Object.defineProperty(Array.prototype, 'includes',function(){
...
})
установить ядро JS
npm install --save core-js- Обратите внимание, что core-js следует устанавливать с помощью метода --save, потому что его необходимо внедрить в исходный код, а перед выполнением кода предоставляется среда выполнения для реализации внедрения встроенных
-
Настроить useBuiltIns
Управляйте встроенной инъекцией с помощью параметра useBuiltIns в @babel/preset-env. Он может быть установлен на «запись», «использование» и «ложь». По умолчанию установлено значение false, прокладки не вводятся.
Когда установлено значение «вход»,Просто импортируйте core-js в точку входа всего проекта.
// src/index.js
import 'core-js'
const add = (a, b) => a + b
const arr = [1, 2]
const hasThreee = arr.includes(3)
new Promise()
// dist/index.js
"use strict";
require("core-js/modules/es7.array.includes");
require("core-js/modules/es6.promise");
//
// …… 这里还有很多
//
require("regenerator-runtime/runtime");
var add = function add(a, b) {
return a + b;
};
var arr = [1, 2];
var hasThreee = arr.includes(3);
new Promise();- После компиляции Babel внедрит все встроенные модули, которые не поддерживаются целевой средой. Независимо от того, используется он или нет, есть проблема. Это совершенно не нужно для проектов, которые используют относительно небольшое количество. Это добавляет код и лишние траты. пакеты размер кузова.
Когда установлено «использование», вам не нужно импортировать core-js при входе в проект, Babel выберет внедрение соответствующей реализации в соответствии с использованием встроенного в процессе компиляции исходного кода.
// src/index.js
const add = (a, b) => a + b
const arr = [1, 2]
const hasThreee = arr.includes(3)
new Promise()
// dist/index.js
"use strict";
require("core-js/modules/es6.promise");
require("core-js/modules/es6.object.to-string");
require("core-js/modules/es7.array.includes");
var add = function add(a, b) {
return a + b;
};
var arr = [1, 2];
var hasThreee = arr.includes(3);
new Promise();- Настройте версию corejs
Когда для параметра useBuiltIns установлено значение «использование» или «запись», вам также необходимо установить параметр corejs в @babel/preset-env, чтобы указать версию corejs, используемую при внедрении реализации встроенного. В противном случае в журнале Babel появится предупреждение.
Окончательная конфигурация Babel выглядит следующим образом:
// babel.config.js
const presets = [
[
'@babel/env',
{
debug: true,
useBuiltIns: 'usage',
corejs: 3,
targets: {}
}
]
]
const plugins = ['@babel/plugin-proposal-class-properties']
module.exports = { presets, plugins }(3) @babel/plugin-transform-runtime
Прежде чем представить цель @babel/plugin-transform-runtime, предыдущий пример:
// src/index.js
const add = (a, b) => a + b
const arr = [1, 2]
const hasThreee = arr.includes(3)
new Promise(resolve=>resolve(10))
class Person {
static a = 1;
static b;
name = 'morrain';
age = 18
}
// dist/index.js
"use strict";
require("core-js/modules/es.array.includes");
require("core-js/modules/es.object.define-property");
require("core-js/modules/es.object.to-string");
require("core-js/modules/es.promise");
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var add = function add(a, b) {
return a + b;
};
var arr = [1, 2];
var hasThreee = arr.includes(3);
new Promise(function (resolve) {
return resolve(10);
});
var Person = function Person() {
_classCallCheck(this, Person);
_defineProperty(this, "name", 'morrain');
_defineProperty(this, "age", 18);
};
_defineProperty(Person, "a", 1);
_defineProperty(Person, "b", void 0);
И @babel/plugin-transform-runtime был создан для повторного использования этих вспомогательных функций и уменьшения размера кода. Конечно, в дополнение к этому, он также может предоставить среду песочницы для скомпилированного кода, чтобы избежать глобального загрязнения.
Используйте @babel/plugin-transform-runtime
①Установка
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
2 Изменить конфигурацию плагинов Babel, добавить @ Babel/plugin-transform-runtime
// babel.config.js
const presets = [
[
'@babel/env',
{
debug: true,
useBuiltIns: 'usage',
corejs: 3,
targets: {}
}
]
]
const plugins = [
'@babel/plugin-proposal-class-properties',
[
'@babel/plugin-transform-runtime'
]
]
module.exports = { presets, plugins }- В предыдущем примере после повторной компиляции видно, что предыдущие вспомогательные функции стали реализациями, аналогичными require("@babel/runtime/helpers/classCallCheck").
// dist/index.js
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
require("core-js/modules/es.array.includes");
require("core-js/modules/es.object.to-string");
require("core-js/modules/es.promise");
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var add = function add(a, b) {
return a + b;
};
var arr = [1, 2];
var hasThreee = arr.includes(3);
new Promise(function (resolve) {
return resolve(10);
});
var Person = function Person() {
(0, _classCallCheck2["default"])(this, Person);
(0, _defineProperty2["default"])(this, "name", 'morrain');
(0, _defineProperty2["default"])(this, "age", 18);
};
(0, _defineProperty2["default"])(Person, "a", 1);
(0, _defineProperty2["default"])(Person, "b", void 0);- Настройте @babel/plugin-transform-runtime
До сих пор синтаксис для встроенных типов реализовывался с помощью полифилла require("core-js/modules/xxxx"). Например, для поддержки метода Array.prototype.includes требуется, чтобы
("core-js/modules/es.array.includes") реализуется добавлением метода include в Array.prototype, но это вызовет проблему, он напрямую модифицирует прототип, что вызовет глобальное загрязнение. Если вы разрабатываете самостоятельное приложение, то это не большая проблема, но если вы разрабатываете инструментальную библиотеку, на которую ссылаются другие проекты, а сам проект реализует метод Array.prototype.includes, то возникает большая проблема ! И @babel/plugin-transform-runtime может решить эту проблему, просто настройте параметр corejs @babel/plugin-transform-runtime. Этот параметр по умолчанию имеет значение false и может быть установлен на 2 или 3, что соответствует @babel/runtime-corejs2 и @babel/runtime-corejs3 соответственно.
Установите значение corejs в @babel/plugin-transform-runtime на 3 и замените @babel/runtime на @babel/runtime-corejs3.
Удалите конфигурацию useBuiltIns и corejs @babel/preset-env и удалите core-js. Поскольку @babel/runtime-corejs3 используется для совместимости с синтаксисом встроенного типа, useBuiltIns больше не нужен.
npm uninstall @babel/runtime
npm install --save @babel/runtime-corejs3
npm uninstall core-js// babel.config.js
const presets = [
[
'@babel/env',
{
debug: true,
targets: {}
}
]
]
const plugins = [
'@babel/plugin-proposal-class-properties',
[
'@babel/plugin-transform-runtime',
{
corejs: 3
}
]
]
module.exports = { presets, plugins }
// dist/index.js
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/classCallCheck"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/defineProperty"));
var _promise = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/promise"));
var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes"));
var add = function add(a, b) {
return a + b;
};
var arr = [1, 2];
var hasThreee = (0, _includes["default"])(arr).call(arr, 3);
new _promise["default"](function (resolve) {
return resolve(10);
});
var Person = function Person() {
(0, _classCallCheck2["default"])(this, Person);
(0, _defineProperty2["default"])(this, "name", 'morrain');
(0, _defineProperty2["default"])(this, "age", 18);
};
(0, _defineProperty2["default"])(Person, "a", 1);
(0, _defineProperty2["default"])(Person, "b", void 0);
3. Различия в реализации полифилла Babel
На данный момент существует три способа полифилла синтаксиса встроенных типов:
С @babel/preset-env для useBuiltIns установлено значение «запись».
С @babel/preset-env для useBuiltIns установлено значение «использование».
Используйте @babel/plugin-transform-runtime
Первые два метода поддерживают установку целей, которые можно адаптировать в соответствии с целевой средой. UseBuiltIns со значением «entry» будет внедрять весь синтаксис встроенного типа, не поддерживаемый целевой средой, useBuiltIns со значением «usage» будет внедрять весь используемый синтаксис встроенного типа, не поддерживаемый целевой средой. Синтаксис внедряемых встроенных типов загрязняет файл global.
Третий способ на данный момент не поддерживает установку целей, поэтому не учитывает, поддерживает ли его уже целевая среда, реализует все настройки через локальные переменные.использоватьсяСинтаксис встроенного типа не загрязняет глобальный.
Babel рассматривает возможность решения проблемы, что третий метод не поддерживает установку целей Текущий план состоит в том, чтобы пройти Polyfill providerЧтобы унифицировать реализацию полифилла:
Откажитесь от параметров useBuiltIns и corejs в @babel/preset-env и больше не реализуйте полифилл через @babel/preset-env.
Устарел параметр corejs в @babel/plugin-transform-runtime и больше не выполняется полифил через @babel/plugin-transform-runtime.
Добавлен параметр polyfills, аналогичный текущим пресетам и плагинам, для замены текущей схемы полифилла.
Поднимите параметр target в @babel/preset-env на один уровень выше, до того же уровня, что и пресеты, плагины и полифиллы, и поделитесь ими.
После реализации этого решения конфигурация Babel будет выглядеть так:
// babel.config.js
const targets = [
'>1%'
]
const presets = [
[
'@babel/env',
{
debug: true
}
]
]
const plugins = [
'@babel/plugin-proposal-class-properties'
]
const polyfills = [
[
'corejs3',
{
method: 'usage-pure'
}
]
]
module.exports = { targets, presets, plugins, polyfills }
'entry-global' эквивалентно useBuiltIns: 'entry' в @babel/preset-env
'usage-global' эквивалентно useBuiltIns: 'usage' в @babel/preset-env
'usage-pure' эквивалентен corejs в @babel/plugin-transform-runtime
В этой статье, для удобства объяснения, для компиляции файлов используется собственный @babel/cli от Babel, который в реальных условиях чаще используется в сочетании со сторонними инструментами, такими как webpack и rollup.
Итак, в следующем разделе мы поговорим об инструменте упаковки webpack.
5. Ссылки
Больше контента, пожалуйста, обратите вниманиеживые интернет-технологииПубличный аккаунт WeChat
Примечание. Чтобы перепечатать статью, сначала свяжитесь с учетной записью WeChat:Labs2020соединять.