一文讀懂babel-loader、babel-polyfill、babel-transform-runtime的區別和聯繫

在咱們的項目中,若是使用了es6的語法和API時就要用到babel對這些語法進行轉化,使代碼能夠在低版本的瀏覽器上正常運行。css

假若有一段es6代碼(main.js):webpack

async function f() {
  return await 123;
}
f().then(v => console.log(v))

console.log(Object.values({ 1: 2 }));
console.log(Array.isArray([]));
console.log([1, 2, 3].includes(3));
複製代碼

package.jsones6

{
  "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": "^7.4.5",
    "@babel/plugin-transform-runtime": "^7.4.4",
    "@babel/preset-env": "^7.4.5",
    "babel-core": "^7.0.0-bridge.0",
    "babel-jest": "^24.8.0",
    "babel-loader": "^7.1.4",
    "css-loader": "^1.0.1",
    "regenerator-runtime": "^0.13.2",
    "webpack": "^4.34.0",
    "webpack-cli": "^3.3.4"
  },
  "dependencies": {
    "@babel/polyfill": "^7.4.4",
    "@babel/runtime": "^7.4.5",
    "@babel/runtime-corejs2": "^7.4.5"
  }
}

複製代碼

webpack4的配置:web

const path = require('path');
module.exports = {
  mode: "development",
  devtool: "inline-cheap-module-source-map",
  entry: {
    app: ['./main.js']
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, './dist'),
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: ['babel-loader']
      }
    ]
  }
};
複製代碼

註釋掉rules,打包後在IE瀏覽器運行報錯 npm

釋放掉rules,增長.babelrc文件,配置以下:

{
	"presets": [["@babel/preset-env"]],
}
複製代碼

由於單獨使用babel-loader是不能對es6的語法進行解析的,須要配合babel-preset-env。 繼續打包運行json

依然報錯,可是報錯信息發生了變化,由於babel-loader只會對es6的語法進行解析,例如箭頭函數。若是要解析es6的API方法就要引入babel-polyfill或者babel-runtime。promise

babel-polyfill瀏覽器

模擬一個完整的es2015+環境,用於應用程序的開發而不是庫文件,可使用Promise之類的新的內置組件和Array.from和Object.assign之類的靜態方法和 Array.prototype.includes等實例方法,polyfill將添加到全局範圍和本地原型中,所以會污染全局變量。bash

引入babel-polyfill的四種方式:babel

  1. 直接在main.js頂部使用import "@babel/polyfill"
  2. 設置.babelrc
{
	"presets": [["@babel/preset-env", {"useBuiltIns": "entry", "corejs": 2}]],
}
複製代碼

並在main.js頂部使用import "@babel/polyfill"

  1. 設置.babelrc
{
	"presets": [["@babel/preset-env", {"useBuiltIns": false}]],
}
複製代碼

在webpack.config.js中入口配置:

entry: {
    app: ['@babel/polyfill', './main.js']
},
複製代碼

4.設置.babelrc,無需引用@babel/polyfill

{
	"presets": [["@babel/preset-env", {"useBuiltIns": "usage", "corejs": 2}]],
}
複製代碼

該配置會自動加載項目中須要的polyfill,而不是所有引入。

打包以後bundle.js大小的比較:

打包以前:

使用前三種引用方式:

使用第四種引用方式:

可見前三種屬於所有引用,第四種屬於按需引用。固然也能夠從安裝包裏找到所需的墊片手動導入。

babel-runtime

項目中安裝依賴包:

npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
複製代碼

babel-runtime爲生產依賴,transform-runtime爲開發依賴,從這裏便可看出,babel-runtime中包含了全部的核心幫助函數。使用babel-runtime的兩種方式

  1. 在項目文件中手動引入所須要的幫助函數,例如
import Promise from "babel-runtime/core-js/promise";
let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');
複製代碼

項目中只使用了Promise,因此只須要引入Promise的幫助函數便可。查看打包以後的bundle.js,能夠看到Promise被重寫,而不是和babel-polyfill同樣放在global上。可是當項目文件比較多,使用的es6 API也比較多時,手動引入就變的比較繁瑣。這時就須要transform-runtime插件了,該插件會分析項目代碼,自動的引入所需的墊片APIs。使用方法:在.babelrc中配置:

{
    "plugins": [["@babel/plugin-transform-runtime", {"corejs": 2}]]
}
複製代碼

並安裝依賴:

npm install --save @babel/runtime-corejs2
複製代碼

去掉手動引入的core-js/promise文件,打包。能夠看到打包完以後的文件和手動引入的文件大小相同,而且均可以正常在IE中運行。transform-runtime的配置參數corejs默認值爲false,假定用戶將引入全部須要使用的幫助文件,因此爲了達到自動引入的效果須要手動的改成2.不然不會解析es6的代碼。

babel-runtime爲你的代碼提供了一個沙盒環境,因此不會像babel-polyfill同樣污染全局變量,所以適用於開發組件庫。可是babel-runtime不能模擬實例方法,即內置對象原型上的方法,例如Array.prototype.concat。

可是若是babel版本>=7.4.0,設置corejs: 3。一樣安裝依賴

npm install --save @babel/runtime-corejs3
複製代碼

在IE中[1, 2, 3].includes(3)方法能夠正常執行。可見core: 3在core: 2的基礎上解決了babel-runtime不能解析實例方法的弱點。

相關文章
相關標籤/搜索