babel-polyfill


剛接觸bable的同學可能會認為使用了Babel,配置了preset預設后就可以愉快的使用 es6+做開發了,事實上,在默認情況下Babel只會做語法轉換(let、const、class、箭頭函數等),而不做新api的轉換,新的api總結起來分為兩類:

  • 全局對象和全局對象相關的方法,例如Promise、Map、Set、Object.assign......
  • 實例的新方法,例如數組的find、flat等等......

想讓es6+的api在不支持的瀏覽器上運行,就需要借助polyfill技術,它使用一系列低版本的js代碼模擬了瀏覽器原生api的實現,俗稱打補丁。效果對比請點我

要使用babel,需要安裝@babel/core、@babel/preset-env,如果是直接使用babel編譯,還需要安裝@babel/cli。

 

1. 手動引入方式補丁包

在babel 7.4之前,只需要安裝@babel/polyfill這個包就可以了;從7.4版本開始,雖然@babel/polyfill還會更新,但它內部的core-js包版將一直使用2.x,無法使用core-js 3.x中新增的補丁代碼,例如數組的includes方法等,因此官方建議直接安裝core-js和regenerator-runtime這兩個包。

接下來在在項目的入口文件中引入補丁包:

//index.js
import “core-js”
import “regenerator-runtime/runtime”

也可以在webpack配置文件的entry節點引入,例:“entry”:['core-js', 'regenerator-runtime/runtime', './index.js']。

這種方法會引入所有的補丁代碼,導致打包出來的代碼體積巨大,因此還需要使用@babel/preset根據目標瀏覽器版本引入瀏覽器未實現的api補丁。

改進:

babel使用browserslist庫的語法格式來聲明瀏覽器版本,聲明瀏覽器版本既可以在package.json中,也可以在babel配置中,建議在package.json中進行聲明,這樣其他的工具也可以共享該配置。package.json中的聲明方法是增加一個“browserslist”節點,值是數組格式,聲明好后可以通過運行npx browserslist命令檢查聲明是否有效。

接下來在babel的配置文件中為@babel/preset-env增加如下的配置:

 
module.exports = {
	presets: [["@babel/preset-env", {
	useBuiltIns: "entry",
	"corejs": 3,
	}]],
}

注意:如果引入的是@babel/polyfill庫,則corejs版本需要指定為2

 

2. 自動引入方式

開發者無需在入口處引入core-js和regenerator-runtime, babel會根據目標瀏覽器版本+項目中實際用到的api來按需引入,打包出來的代碼體積更小。

要實現自動引入,首先需要在package.json文件中聲明目標瀏覽器及版本,然后可以使用下面兩種方法中的一種:

  • 將@babel/preset-env中的useBuiltIns的值改為usage。
  • 使用@babel/plugin-transform-runtime插件。此種方式不需要安裝core-js、regenerator-runtime,只需要安裝@babel/runtime-corejs3和@babel/plugin-transform-runtime,並將babel配置修改為:
module.exports = {
  presets:['@babel/preset-env'],
  plugins: [
    ["@babel/plugin-transform-runtime", {
      "corejs": 3
    }]
  ]
}

}

 

這兩種方式有何差別?以目標瀏覽器版本為firefox 60、使用數組flat方法為例,兩種方法引入的補丁代碼如下:

方法1:

"use strict";
require("core-js/modules/es.array.flat.js");
require("core-js/modules/es.array.unscopables.flat.js");
var arr = [[1, 2, [3, 4]]];
var b = arr.flat();

方法2:

"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _flat = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/flat"));
var arr = [[1, 2, [3, 4]]];
var b = (0, _flat.default)(arr).call(arr);

 

從上面的代碼對比中可以看到,方法1通過修改Array對象的原型鏈方式實現了api;方法2通過一個局部函數來實現api,避免了對全局對象的污染。既然兩種方法都能實現打補丁,該如何選擇?若是開發項目,應采用方法1,可節省代碼、縮減代碼體積;若是開發組件或庫等具備復用的代碼,應采用方法2,原因是當庫和項目使用了同一api,但庫的兼容目標需要使用補丁代碼,而項目的兼容目標中該api已由瀏覽器原生實現時,若采用方法1,則庫和項目調用該api時,使用的都是js模擬代碼,模擬代碼的執行效率肯定沒有瀏覽器原生api實現代碼執行效率高。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM