Полное руководство по миграции обновления babel-preset-env

Node.js внешний интерфейс JavaScript Babel

Руководство по обновлению 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:类方法简写. Все еще сохраняя исходный код, так что не так с этим? Это включает в себя разницу между тремя способами определения функции:

  1. нормальное разрешение
  2. сокращенное определение
  3. стрелочная функция

Пожалуйста, посмотрите демо ниже:

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

Ссылаться на

  1. Method definitions
  2. FunctionCreate
  3. TypeError: "x" is not a constructor
  4. babel-preset-env
  5. babel-preset-es2015
  6. Совместимость узла ES2015