babel-polyfill VS babel-runtime VS babel-preset-env

внешний интерфейс JavaScript Webpack Babel

            babel-polyfill VS babel-runtime VS babel-preset-env

В процессе разработки проекта нам часто приходится внедрять babel для решения проблемы совместимости кода. В настоящее время существует три метода:babel-polyfill,babel-runtime和babel-preset-env, то в чем разница между этими тремя способами, и какой из них лучше в сочетании с вебпаком, давайте сравним.

Готов к работе

Прежде чем начать сравнение, нам нужно инициализировать проект веб-пакета.

npm init babel-test

Здесь мы не планируем устанавливать версию вебпака 4.X, просто устанавливаем версию 3.X

npm i -D webpack@3.7.0

Создайте новый файл webpack.config.js в корневом каталоге проекта со следующей конфигурацией.

const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  // JavaScript 执行入口文件
  entry: {
    app: ['./main.js']
  },
  output: {
    // 把所有依赖的模块合并输出到一个 bundle.js 文件
    filename: 'bundle.js',
    // 输出文件都放到 dist 目录下
    path: path.resolve(__dirname, './dist'),
  },
  devServer: {
    contentBase: path.join(__dirname, "dist"),
    inline: true
  },
  module: {
    rules: [
      {
        // 用正则去匹配要用该 loader 转换的 CSS 文件
        test: /\.css$/,
        // use: ['style-loader', 'css-loader?minimize'],
        use: ExtractTextPlugin.extract({
          // 转换 .css 文件需要使用的 Loader
          use: ['css-loader']
        })
      },
      {
        test: /\.js$/,
        use: ['babel-loader']
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin({
      // 从 .js 文件中提取出来的 .css 文件的名称
      filename: `[name].css`,
    })
  ]
};

package.json настроен следующим образом

{
  "name": "babel-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack --config webpack.config.js",
    "dev": "webpack-dev-server --open"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.4",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.6.1",
    "css-loader": "^0.28.11",
    "extract-text-webpack-plugin": "^3.0.2",
    "style-loader": "^0.20.3",
    "webpack": "^3.7.0",
    "webpack-cli": "^1.5.3",
    "webpack-dev-server": "^2.11.1"
  },
  "dependencies": {
    "babel-polyfill": "^6.26.0",
    "babel-runtime": "^6.26.0"
  }
}

Задействованные пакеты выполняютсяnpm installПросто установите его, и я не буду вдаваться в подробности здесь. Некоторые из пакетов здесь будут неоднократно упоминаться далее, объясняя, почему они установлены таким образом.

Структура проекта после завершения инициализации проекта выглядит следующим образом.

Пишем код в main.js

const elements = [1, 2, 3].map((item) => {
  return (
    console.log('9999')
  )
});

console.log(elements);

async function azumia() {
  console.log('begin');
  await new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, 1000)
  })
  console.log('done');
}
azumia();

console.log(Object.values({ 1: 2 }));

console.log(Array.isArray([]));

babel-polyfill

babel-polyfill предназначен для эмуляции полной среды ES2015+ и предназначен для использования в приложениях, а не в библиотеках/инструментах. А при использовании babel-node этот полифилл подгружается автоматически. Здесь следует отметить, что babel-polyfill внедряется в ваш проект один раз и компилируется в рабочую среду вместе с кодом проекта. И это загрязнит глобальные переменные. Как и Map, Array.prototype.find они существуют в глобальном пространстве.

Итак, здесь он установлен в производственной среде

npm install babel-polyfill --save

Вы можете настроить это так в webpack.config.js

  entry: {
    app: ['babel-polyfill','./main.js']
  }

Выполним команду для начала упаковки

npm run start

Размер упакованного файла bundle.js составляет259KИ размер пакета, прежде чем присоединиться к Babel-Polyfill только4K, намного больше. Итак, можем ли мы ссылаться на babel-polyfill по запросу, чтобы уменьшить размер пакета? Ответ — да, это достигается с помощью babel-runtime.

babel-runtime

babel-runtime не загрязняет глобальное пространство и встроенные прототипы объектов. На самом деле babel-runtime — это модуль, вы можете использовать его как зависимость для поддержки ES2015.

Например, если среда не поддерживает Promise, вы можете добавить его в проект

require(‘babel-runtime/core-js/promise’)

чтобы получить Обещание.

Таким образом мы компенсируем недостатки babel-polyfill и добиваемся эффекта загрузки по требованию. Однако в реальном процессе разработки проекта мы часто пишем много новых es6 apis.Вручную каждый раз импортировать соответствующий пакет хлопотно, неудобно поддерживать.Повторное введение каждого файла также приводит к тому, что код раздутый.

Для решения этой задачи необходимо использоватьbabel-plugin-transform-runtime, он проанализирует наш ast, чтобы увидеть, есть ли ссылка на прокладку в babel-rumtime (через отношения сопоставления), и если да, то вставит нужную нам прокладку вверху текущего модуля.

Далее мы попробуем, первая установка Babel-Runtime и Babel-Plugin-Transform - Runtime

npm install --save babel-runtime
npm install --save-dev babel-plugin-transform-runtime

Так как babel-runtime концентрирует только библиотеку полифилов, соответствующие полифиллы необходимо внедрить в проект и упаковать с кодом проекта, поэтому их необходимо добавить в зависимости производственной среды.

Добавьте следующую конфигурацию в .babelrc

{
  "plugins": ["transform-runtime"]
}

Выполните команду упаковки, и размер упакованного файла bundle.js будет равен63K, что намного меньше, чем полное внедрение полифиллов. Но у вещей есть две стороны, у babel-runtime есть недостаток,它不模拟实例方法, то есть метод на встроенном объектном прототипе, настолько похожий на Array.prototype.find, что его нельзя использовать через babel-runtime, который можно перекодировать только через babel-polyfill, т.к. babel-polyfill напрямую добавляет методы в цепочке прототипов. Печальное напоминание: нужно ли нам полностью внедрять babel-polyfill?

babel-preset-env

babel-preset-env может автоматически определять необходимые вам плагины и полифилы на основе текущей рабочей среды. За счет поддержки каждой стандартной функции es в разных браузерах и версиях узлов, а затем поддержания связи между функцией и плагинами и, наконец, определения необходимых плагинов. Подробные инструкции по настройке см.кликните сюда

Давайте изменим конфигурацию .babelrc

{
  "presets": [
    ["env", {
      "targets": {
        "chrome": 52,
        "browsers": ["last 2 versions", "safari 7"]
      },
      "modules": false,
      "useBuiltIns": "usage",
      "debug": false
    }]
  ]
}

Среди них useBuiltIns — включить ли автоматическую поддержку полифилла, которая может автоматически добавлять требуемый полифилл в каждый файл. Давайте попробуем, babel-polyfill отражен в main.js

require('babel-polyfill')

Вы не ошиблись, он должен быть введен в main.js, и кажется, что его невозможно настроить непосредственно в веб-пакете.

После выполнения команды package размер bundle.js составляет194K, что относительно мало.

Если вы откроете страницу в браузере в это время, то обнаружите следующую ошибку

Подскажите причину и решение этой проблемыкликните сюда, давайте изменим метод введения babel-polyfill, изменим require на import, и введение будет продвинуто на передний план.

 - require('babel-polyfill')
 + import 'babel-polyfill'

После упаковки снова

Суммировать

Сравнивая вышеприведенные три схемы, делаем следующие выводы

строить планы размер после упаковки преимущество недостаток
babel-polyfill 259K Полное моделирование среды ES2015+ Слишком большой; загрязняет глобальные объекты и встроенные прототипы объектов
babel-runtime 63K Вводится по запросу, небольшой размер упаковки Не имитируйте методы экземпляра
babel-preset-env (открыть useBuiltIns) 194K Внедрение по запросу, широкие возможности настройки -

У схемы нет абсолютного преимущества или недостатка, и ее следует использовать гибко в соответствии с реальной ситуацией в процессе разработки.

  • Справочная документация

Вы действительно знаете, как использовать Babel?

babel-polyfill VS babel-runtime