Руководство по обновлению Babel-preset-env
предисловие
В сентябре Babel объявил, что ES2015/ES2016/ES2017 и другие пресеты эпохи ES20xx были заброшены и заменены наbabel-preset-env
, и обещает, что это будет решение, ориентированное на будущее. Поэтому, когда мы переустановим эти пакеты es20xx, будет выдано следующее приглашение:
npm WARN deprecated babel-preset-es2015@6.24.1: Thanks for using Babel: we recommend using babel-preset-env now: please read babeljs.io/env to update!
Это указывает на то, что если мы хотим использовать новейшие функции в будущем, нам больше не нужно устанавливать различные предустановки esxx, и нам нужен только один пакет для всего. Для интерфейса нашего поиска новых функций такое обновление является обязательным, поэтому я попробовал его и начал свой путь обновления и миграции.
Перед обновлением давайте взглянем на некоторые новые функции этого пакета.
babel-preset-envПринцип реализации
Ознакомьтесь с введением на официальном сайте Этот пресет может автоматически выбирать плагины и полифилы Babel для компиляции кода ES2015+ через целевой браузер или среду выполнения в реальном времени, которую вы настроили. Затем мы можем передать исходный кодpackage.json
чтобы увидеть, сколько плагинов поддерживает пресет (в исходном кодеavailable-plugins.jsЕсть ссылки на эти плагины):
"babel-plugin-check-es2015-constants": "7.0.0-beta.2",
"babel-plugin-syntax-async-generators": "7.0.0-beta.0",
"babel-plugin-syntax-object-rest-spread": "7.0.0-beta.0",
"babel-plugin-syntax-optional-catch-binding": "7.0.0-beta.0",
"babel-plugin-syntax-trailing-function-commas": "7.0.0-beta.0",
"babel-plugin-transform-async-to-generator": "7.0.0-beta.2",
"babel-plugin-transform-async-generator-functions": "7.0.0-beta.2",
"babel-plugin-transform-es2015-arrow-functions": "7.0.0-beta.2",
"babel-plugin-transform-es2015-block-scoped-functions": "7.0.0-beta.2",
"babel-plugin-transform-es2015-block-scoping": "7.0.0-beta.2",
"babel-plugin-transform-es2015-classes": "7.0.0-beta.2",
"babel-plugin-transform-es2015-computed-properties": "7.0.0-beta.2",
"babel-plugin-transform-es2015-destructuring": "7.0.0-beta.2",
"babel-plugin-transform-es2015-duplicate-keys": "7.0.0-beta.2",
"babel-plugin-transform-es2015-for-of": "7.0.0-beta.2",
"babel-plugin-transform-es2015-function-name": "7.0.0-beta.2",
"babel-plugin-transform-es2015-literals": "7.0.0-beta.2",
"babel-plugin-transform-es2015-modules-amd": "7.0.0-beta.2",
"babel-plugin-transform-es2015-modules-commonjs": "7.0.0-beta.2",
"babel-plugin-transform-es2015-modules-systemjs": "7.0.0-beta.2",
"babel-plugin-transform-es2015-modules-umd": "7.0.0-beta.2",
"babel-plugin-transform-es2015-object-super": "7.0.0-beta.2",
"babel-plugin-transform-es2015-parameters": "7.0.0-beta.2",
"babel-plugin-transform-es2015-shorthand-properties": "7.0.0-beta.2",
"babel-plugin-transform-es2015-spread": "7.0.0-beta.2",
"babel-plugin-transform-es2015-sticky-regex": "7.0.0-beta.2",
"babel-plugin-transform-es2015-template-literals": "7.0.0-beta.2",
"babel-plugin-transform-es2015-typeof-symbol": "7.0.0-beta.2",
"babel-plugin-transform-es2015-unicode-regex": "7.0.0-beta.2",
"babel-plugin-transform-exponentiation-operator": "7.0.0-beta.2",
"babel-plugin-transform-new-target": "7.0.0-beta.2",
"babel-plugin-transform-regenerator": "7.0.0-beta.2",
"babel-plugin-transform-object-rest-spread": "7.0.0-beta.2",
"babel-plugin-transform-optional-catch-binding": "7.0.0-beta.2",
"babel-plugin-transform-unicode-property-regex": "^2.0.5",
В дополнение к этим плагинам есть несколько встроенных определений, в том числе новые методы для Array и т. д. в исходном кодеsrc/built-in-definitions.jsИмеются соответствующие ссылки. Но он может быть не очень полным. Например, нетArray.includes()
пакет методов.
Такbabel-preset-env
как это установлено у насtarget
Автоматически загружать соответствующие плагины и встроенные методы?
Прочитав код можно найти в/data/
Поддержка всех плагинов и встроенных методов поддерживается в каталоге, например, в/data/plugin.json
середина:
"transform-es2015-arrow-functions": {
"chrome": "47",
"edge": "13",
"firefox": "45",
"safari": "10",
"node": "6",
"ios": "10",
"opera": "34",
"electron": "0.36"
}
Перечислена поддержка стрелочных функций, которая поддерживается начиная с Chrome 47, и другие браузеры также могут ее увидеть с первого взгляда. Затем, опираясь на поддержку этих плагинов, в/src/index.js
В этой функции для определения текущей настройкиtarget
Вам нужно загрузить плагин:
export const isPluginRequired = (
supportedEnvironments: Targets,
plugin: Targets,
): boolean => {
......
}
Отсюда у нас есть список плагинов или встроенных методов для данной среды.
Вычислятьbabel-preset-env
После принципа реализации у нас будет определенная степень уверенности в последующем процессе миграции и обновления, а не в состоянии проб и ошибок.
Что касается других реализаций в коде, таких как парсинг таргета и загрузка встроенного метода, вы можете прочитать исходный код, когда у вас будет время, возможно, вам понадобится реализовать такую же функцию в следующий раз?
babel-preset-env
миграция обновления
Чтобы мы могли сравнить эффекты, мы возьмем конфигурацию до миграции и конфигурацию после миграции, чтобы облегчить наше сравнение.В конце концов, версия до миграции должна быть стабильной версией. В то же время мы сделаем соответствующую миграцию с интерфейсными js и nodejs соответственно. Далее дается фронтенд до миграции (мобильный)из.babelrc
и на стороне nodejs.babelrc
Конфигурация файла:
внешний интерфейс:
{
"presets": [
["es2015", {"modules": false}],
"react",
"stage-1"
],
"plugins": [
"transform-async-to-generator",
"transform-decorators-legacy",
"transform-object-rest-spread",
"transform-runtime",
]
}
сторона узла:
{
"presets": [
"es2015",
"react",
"stage-0"
],
"plugins": [
"transform-class-properties",
"transform-async-to-generator",
"transform-decorators-legacy",
"transform-object-rest-spread"
]
}
Во-первых, давайте поговорим о передней части.
Интерфейсная миграция и обновление
Сначала мы знаемbabel-preset-es2015
Что представляют собой соответствующие подключаемые модули, а также настроенные дополнительные подключаемые модули, пожалуйста, обратитесь к Таблице 1 ниже для получения приблизительного списка подключаемых модулей.
ок, старая конфигурация и примерный список плагинов у нас получились, теперь пользуемсяbabel-preset-env
Получите еще один список плагинов.
Согласно объяснению официальной документации, вам нужно только.babelrc
в файлеpreset
варианты примерноes2015
/es2016
/es2017
/latest
заменитьenv
Вот и все. Поэтому мы используем это.babelrc
файл, потому что это мобильный терминал, поэтому, когда мы настраиваем цель, мы используем систему в качестве логотипа.
{
"presets": [
["env", {
"targets": {
"browsers": ["Android >= 4.0", "ios >= 6"]
},
"debug": true,
"include": [],
"useBuiltIns": false
}],
"react",
"stage-0"
],
"plugins": [
"transform-runtime",
"transform-decorators-legacy",
"transform-object-rest-spread"
]
}
сделай этоbabel
команда, потому что этоdebug=true
, так что вы можете видеть, что соответствующий отпечаток:
Using targets:
{
"android": "4",
"ios": "6"
}
Modules transform: commonjs
Using plugins:
check-es2015-constants {"android":"4","ios":"6"}
transform-es2015-arrow-functions {"android":"4","ios":"6"}
transform-es2015-block-scoped-functions {"android":"4","ios":"6"}
transform-es2015-block-scoping {"android":"4","ios":"6"}
transform-es2015-classes {"android":"4","ios":"6"}
transform-es2015-computed-properties {"android":"4","ios":"6"}
transform-es2015-destructuring {"android":"4","ios":"6"}
transform-es2015-duplicate-keys {"android":"4","ios":"6"}
transform-es2015-for-of {"android":"4","ios":"6"}
transform-es2015-function-name {"android":"4","ios":"6"}
transform-es2015-literals {"android":"4","ios":"6"}
transform-es2015-object-super {"android":"4","ios":"6"}
transform-es2015-parameters {"android":"4","ios":"6"}
transform-es2015-shorthand-properties {"android":"4","ios":"6"}
transform-es2015-spread {"android":"4","ios":"6"}
transform-es2015-sticky-regex {"android":"4","ios":"6"}
transform-es2015-template-literals {"android":"4","ios":"6"}
transform-es2015-typeof-symbol {"android":"4","ios":"6"}
transform-es2015-unicode-regex {"android":"4","ios":"6"}
transform-regenerator {"android":"4","ios":"6"}
transform-exponentiation-operator {"android":"4","ios":"6"}
transform-async-to-generator {"android":"4","ios":"6"}
syntax-trailing-function-commas {"android":"4","ios":"6"}
Добавьте плагины с дополнительной настройкой и сравните полученный список плагинов со списком плагинов, полученным в предыдущей конфигурации:
Таблица 1: Сравнение списков новых и старых подключаемых модулей конфигурации
плагин | старая конфигурация | новая конфигурация |
---|---|---|
check-es2015-constants | Y | Y |
transform-es2015-arrow-functions | Y | Y |
transform-es2015-block-scoped-functions | Y | Y |
transform-es2015-block-scoping | Y | Y |
transform-es2015-classes | Y | Y |
transform-es2015-computed-properties | Y | Y |
transform-es2015-destructuring | Y | Y |
transform-es2015-duplicate-keys | Y | Y |
transform-es2015-for-of | Y | Y |
transform-es2015-function-name | Y | Y |
transform-es2015-literals | Y | Y |
transform-es2015-modules-commonjs | Y | Y (напечатайте, что говорит эта строка: Преобразование модулей: commonjs) |
transform-es2015-object-super | Y | Y |
transform-es2015-parameters | Y | Y |
transform-es2015-shorthand-properties | Y | Y |
transform-es2015-spread | Y | Y |
transform-es2015-sticky-regex | Y | Y |
transform-es2015-template-literals | Y | Y |
transform-es2015-typeof-symbol | Y | Y |
transform-es2015-unicode-regex | Y | Y |
transform-regenerator | Y | Y |
transform-exponentiation-operator | N | Y |
syntax-trailing-function-commas | N | Y |
transform-async-to-generator | Y | Y |
transform-decorators-legacy | Y | Y |
transform-object-rest-spread | Y | Y |
transform-runtime | Y | Y |
Очевидно, что наша конфигурация более полная, чем старая.
В это время у знакомых с этим плагином детской обуви могут возникнуть вопросы: почему эти плагины не настроены в предустановленном?include
внутри поля? Поскольку, согласно объяснению официальной документации,include
Плагин, в котором размещено поле, должен существовать в этом списке.plugin-features.js, иначе будет сообщено об ошибке.
На этом наша миграция внешнего интерфейса завершена. Далее мы хотим сделать некоторые обновления, что обновить?
В обычном написании кода уже используется множество встроенных методов, но иногда возникает такая нехорошая ситуация:
На некоторых более ранних версиях мобильных телефонов сообщается об ошибке на странице или страница даже не может быть открыта только потому, что мы используем ее на этапе willMount компонента.includes/find
и другие встроенные методы. Но поскольку в нашей предыдущей конфигурации не было настроено преобразование этих встроенных методов, ни один из этих методов не будет скомпилирован.
использоватьbabel-polyfill
Компиляцию этих методов можно реализовать в старой конфигурации, но поскольку она недостаточно гибкая, мы вводим весь пакет, что приводит к ненужным накладным расходам. Но в новой конфигурации нам достаточно включить переключатель, чтобы добиться:useBuiltIns=true
, Согласно официальной документации:
Это поле даетbabel-preset-env
Предоставляет способ полифилла (но также черезbabel-polyfill
). Просто метод стал загружать соответствующую серию переводов плагинов и заменять прямые ссылки в соответствии с настроенным на данный момент окружением.babel-polyfill
. Например, мы обновляем следующую конфигурацию:
{
"presets": [
["env", {
"targets": {
"browsers": ["Android >= 4.0", "ios >= 6"]
},
"debug": true,
"include": [],
"useBuiltIns": true
}],
"react",
"stage-1"
],
"plugins": [
"transform-runtime",
"transform-decorators-legacy",
"transform-object-rest-spread"
]
}
Тогда отладочная печать выглядит следующим образом:
Using polyfills:
es6.typed.array-buffer {"android":"4","ios":"6"}
es6.typed.int8-array {"android":"4","ios":"6"}
es6.typed.uint8-array {"android":"4","ios":"6"}
es6.typed.uint8-clamped-array {"android":"4","ios":"6"}
es6.typed.int16-array {"android":"4","ios":"6"}
es6.typed.uint16-array {"android":"4","ios":"6"}
es6.typed.int32-array {"android":"4","ios":"6"}
es6.typed.uint32-array {"android":"4","ios":"6"}
es6.typed.float32-array {"android":"4","ios":"6"}
es6.typed.float64-array {"android":"4","ios":"6"}
es6.map {"android":"4","ios":"6"}
es6.set {"android":"4","ios":"6"}
es6.weak-map {"android":"4","ios":"6"}
es6.weak-set {"android":"4","ios":"6"}
es6.reflect.apply {"android":"4","ios":"6"}
es6.reflect.construct {"android":"4","ios":"6"}
es6.reflect.define-property {"android":"4","ios":"6"}
es6.reflect.delete-property {"android":"4","ios":"6"}
es6.reflect.get {"android":"4","ios":"6"}
es6.reflect.get-own-property-descriptor {"android":"4","ios":"6"}
es6.reflect.get-prototype-of {"android":"4","ios":"6"}
es6.reflect.has {"android":"4","ios":"6"}
es6.reflect.is-extensible {"android":"4","ios":"6"}
es6.reflect.own-keys {"android":"4","ios":"6"}
es6.reflect.prevent-extensions {"android":"4","ios":"6"}
es6.reflect.set {"android":"4","ios":"6"}
es6.reflect.set-prototype-of {"android":"4","ios":"6"}
es6.promise {"android":"4","ios":"6"}
es6.symbol {"android":"4","ios":"6"}
es6.object.freeze {"android":"4","ios":"6"}
es6.object.seal {"android":"4","ios":"6"}
es6.object.prevent-extensions {"android":"4","ios":"6"}
es6.object.is-frozen {"android":"4","ios":"6"}
es6.object.is-sealed {"android":"4","ios":"6"}
es6.object.is-extensible {"android":"4","ios":"6"}
es6.object.get-own-property-descriptor {"android":"4","ios":"6"}
es6.object.get-prototype-of {"android":"4","ios":"6"}
es6.object.keys {"android":"4","ios":"6"}
es6.object.get-own-property-names {"android":"4","ios":"6"}
es6.object.assign {"android":"4","ios":"6"}
es6.object.is {"android":"4","ios":"6"}
es6.object.set-prototype-of {"android":"4","ios":"6"}
es6.function.name {"android":"4","ios":"6"}
es6.string.raw {"android":"4","ios":"6"}
es6.string.from-code-point {"android":"4","ios":"6"}
es6.string.code-point-at {"android":"4","ios":"6"}
es6.string.repeat {"android":"4","ios":"6"}
es6.string.starts-with {"android":"4","ios":"6"}
es6.string.ends-with {"android":"4","ios":"6"}
es6.string.includes {"android":"4","ios":"6"}
es6.regexp.flags {"android":"4","ios":"6"}
es6.regexp.match {"android":"4","ios":"6"}
es6.regexp.replace {"android":"4","ios":"6"}
es6.regexp.split {"android":"4","ios":"6"}
es6.regexp.search {"android":"4","ios":"6"}
es6.array.from {"android":"4","ios":"6"}
es6.array.of {"android":"4","ios":"6"}
es6.array.copy-within {"android":"4","ios":"6"}
es6.array.find {"android":"4","ios":"6"}
es6.array.find-index {"android":"4","ios":"6"}
es6.array.fill {"android":"4","ios":"6"}
es6.array.iterator {"android":"4","ios":"6"}
es6.number.is-finite {"android":"4","ios":"6"}
es6.number.is-integer {"android":"4","ios":"6"}
es6.number.is-safe-integer {"android":"4","ios":"6"}
es6.number.is-nan {"android":"4","ios":"6"}
es6.number.epsilon {"android":"4","ios":"6"}
es6.number.min-safe-integer {"android":"4","ios":"6"}
es6.number.max-safe-integer {"android":"4","ios":"6"}
es6.math.acosh {"android":"4","ios":"6"}
es6.math.asinh {"android":"4","ios":"6"}
es6.math.atanh {"android":"4","ios":"6"}
es6.math.cbrt {"android":"4","ios":"6"}
es6.math.clz32 {"android":"4","ios":"6"}
es6.math.cosh {"android":"4","ios":"6"}
es6.math.expm1 {"android":"4","ios":"6"}
es6.math.fround {"android":"4","ios":"6"}
es6.math.hypot {"android":"4","ios":"6"}
es6.math.imul {"android":"4","ios":"6"}
es6.math.log1p {"android":"4","ios":"6"}
es6.math.log10 {"android":"4","ios":"6"}
es6.math.log2 {"android":"4","ios":"6"}
es6.math.sign {"android":"4","ios":"6"}
es6.math.sinh {"android":"4","ios":"6"}
es6.math.tanh {"android":"4","ios":"6"}
es6.math.trunc {"android":"4","ios":"6"}
es7.array.includes {"android":"4","ios":"6"}
es7.object.values {"android":"4","ios":"6"}
es7.object.entries {"android":"4","ios":"6"}
es7.object.get-own-property-descriptors {"android":"4","ios":"6"}
es7.string.pad-start {"android":"4","ios":"6"}
es7.string.pad-end {"android":"4","ios":"6"}
web.timers {"android":"4","ios":"6"}
web.immediate {"android":"4","ios":"6"}
web.dom.iterable {"android":"4","ios":"6"}
После приблизительного просмотра я добавил много встроенных методов,Если метод, который вы хотите использовать, по-прежнему недоступен, вы можете настроить его только в поле плагинов., например, я хочу использоватьincludes
метод, то его можно настроить только так:
"plugins": [
"array-includes"
]
На данный момент интерфейс считается перенесенным и обновленным, соответствующую конфигурацию и демонстрацию можно найти здесь:babel-preset-env-demo
Миграция и обновление на стороне nodejs
В соответствии с предыдущими идеями миграции и обновления внешнего интерфейса нам нетрудно получить следующую новую конфигурацию: (при условии, что наша версия Nodejs 6.4)
{
"presets": [
["env", {
"targets": {
"node": "6.4"
},
"debug": true,
"useBuiltIns": true,
"include": [
]
}],
"react",
"stage-0"
],
"plugins": [
"transform-class-properties",
"transform-decorators-legacy",
"transform-object-rest-spread",
"array-includes"
]
}
Если вы думаете, что даже если миграция и обновление будут завершены, то вы действительно слишком молоды и слишком просты. Большая разница в этой конфигурации заключается в том, что наша цель изменилась, поэтому вполне возможно, что плагины и встроенные методы соответствующего приложения также должны были измениться, и печать выглядит следующим образом:
Using targets:
{
"node": "6.4"
}
Modules transform: commonjs
Using plugins:
transform-es2015-destructuring {"node":"6.4"}
transform-es2015-for-of {"node":"6.4"}
transform-es2015-function-name {"node":"6.4"}
transform-exponentiation-operator {"node":"6.4"}
transform-async-to-generator {"node":"6.4"}
syntax-trailing-function-commas {"node":"6.4"}
Using polyfills:
es6.typed.array-buffer {"node":"6.4"}
es6.typed.int8-array {"node":"6.4"}
es6.typed.uint8-array {"node":"6.4"}
es6.typed.uint8-clamped-array {"node":"6.4"}
es6.typed.int16-array {"node":"6.4"}
es6.typed.uint16-array {"node":"6.4"}
es6.typed.int32-array {"node":"6.4"}
es6.typed.uint32-array {"node":"6.4"}
es6.typed.float32-array {"node":"6.4"}
es6.typed.float64-array {"node":"6.4"}
es6.map {"node":"6.4"}
es6.set {"node":"6.4"}
es6.weak-map {"node":"6.4"}
es6.weak-set {"node":"6.4"}
es6.promise {"node":"6.4"}
es6.symbol {"node":"6.4"}
es6.function.name {"node":"6.4"}
es6.array.from {"node":"6.4"}
es7.object.values {"node":"6.4"}
es7.object.entries {"node":"6.4"}
es7.object.get-own-property-descriptors {"node":"6.4"}
es7.string.pad-start {"node":"6.4"}
es7.string.pad-end {"node":"6.4"}
Можно обнаружить, что использование плагинов на странице внешнего интерфейса значительно сократилось, в конце концов, это node6! Если это Node8, то точно меньше. Изначально этих плагинов должно быть достаточно для нашего повседневного использования, но одно из моих применений в проекте напрямую вызвало ошибку, которая лишила меня дара речи. Вот демо:
// module.js
module.exports = {
error(message){
this.name = 'Dianwoda';
this.message = message || '系统异常,请稍后再试';
this.type = 'customeErrorType'
this.stack = (new Error()).stack;
}
}
// main.js
const mod = require('./module.js')
(() => {
throw new mod.error('这里抛自定义的错误')
})
Умная детская обувь увидела проблему с этим кодом? Сообщит об ошибке? О какой ошибке сообщается?
5
4
3
2
1
При текущей конфигурации babel код сообщит об ошибке, и содержание ошибки должно бытьmod.error is not a constructor
!Зачем?
Ответ заключается в том, что в этой конфигурации babel не поможет вам перевести новый синтаксис ES6:类方法简写
. Все еще сохраняя исходный код, так что не так с этим? Это включает в себя разницу между тремя способами определения функции:
- нормальное разрешение
- сокращенное определение
- стрелочная функция
Пожалуйста, посмотрите демо ниже:
const example = {
normal: function() { console.log(this); },
arrow: () => { console.log(this); },
shorthand() { console.log(this); }
};
new example.fn(); // fn {}
new example.arrow(); // Uncaught TypeError: example.arrow is not a constructor
new example.shorthand(); // Uncaught TypeError: example.shorthand is not a constructor
существуетMethod definitionsЕсть такая фраза:
Method definitions are not constructable
Понятно, что все функции, определенные всем третьим способом, не признаются. Мы можем распечатать структуру три в Chrome.
Поэтому естественно сообщать об ошибках такого рода в текущей конфигурации Babel. Затем мы изменим конфигурацию и добавим соответствующие плагины:
...
"include": [
"transform-es2015-shorthand-properties"
]
...
Таким образом, сокращенные свойства ES6 могут быть переведены в обычные объявления функций, так что эта проблема решена.
Такая конфигурация в основном удовлетворяет нашему использованию в проекте.Для демонстрации этой конфигурации, пожалуйста, обратитесь к:babel-preset-env-demo