babel6和babel7中关于polyfill和preset-env和babel-plugin-transform-runtime等总结
記錄自己零散的收獲,隨筆。
一些基礎(chǔ)
babel的作用是轉(zhuǎn)換JS新的特性代碼為大部分瀏覽器能運(yùn)行的代碼。
babel轉(zhuǎn)碼又分為兩部分,一個(gè)是語法轉(zhuǎn)換,一個(gè)是API轉(zhuǎn)換。
對于API的轉(zhuǎn)換又分為兩部分,一個(gè)是全局API例如Promise,Set,Map還有靜態(tài)方法Object.assign,另一個(gè)是實(shí)例方法例如Array.prototype.includes。對于實(shí)例方法core-js@2是轉(zhuǎn)換不了的,只有core-js@3才會轉(zhuǎn)換。
babel代碼轉(zhuǎn)換依賴plugin,沒有plugin的情況下babel做的事情只是 code => code。
plugin 有很多,一個(gè)個(gè)導(dǎo)入又特別麻煩,這時(shí)候我們又知道了preset。
preset是很多plugin的集合,配置如下:
.babelrc文件
{"presets": ["env"] }如果preset-env是有配置項(xiàng)的:
{"presets": [["env",{// 這里就是配置項(xiàng)}]] }可以觀察出如果某個(gè)preset需要配置可以將字符串換成一個(gè)數(shù)組,第一項(xiàng)是preset的name,第二項(xiàng)就是options。plugin同preset。
注:preset是從右往左執(zhí)行,plugin是從左往右執(zhí)行,并且plugin先于preset執(zhí)行。
babel6到babel7的升級是具有破壞性的,主要總結(jié)下polyfill的用法和在babel6和babel7中的不同。
babel-polyfill
上面說到babel主要做兩件事,一個(gè)是轉(zhuǎn)換語法,一個(gè)是兼容新的API。
babel-polyfill 的作用是兼容新的API。
babel7
babel7進(jìn)行了較大的改動,廢棄了 stage-x的preset,還增加了命名空間區(qū)分官方插件和非官方插件,@babel/core,@babel/cli等。
建議使用@babel/preset-env 。
@babel/plugin-transform-runtime
該插件的引入主要有兩個(gè)作用
在babel7中,原先的插件babel-plugin-transform-runtime也做了修改 -> @babel/plugin-transform-runtime。并且在功能上也變強(qiáng)大了。
移除了polyfill的配置項(xiàng)添,加了corejs配置項(xiàng)。
@babel/plugin-transform-runtime的默認(rèn)配合如下:
{plugins: [["@babel/plugin-transform-runtime", {"absoluteRuntime": false, // 不是很清除干啥的"corejs": false, // 下面詳解"helpers": true, // 助手函數(shù)是否提取,同babel-plugin-transform"regenerator": true, // 同babel-plugin-transform"useESModules": false}]] }對于配置項(xiàng) corejs: false | 2 | 3。
false 依賴 @babel/runtime,是默認(rèn)選項(xiàng),認(rèn)為需要填充的API以被填充,所以不對API作polyfill(對于@babel/runtime的依賴是提取的helper的依賴)。
2 依賴@babel/runtime-corejs2
3 依賴@babel/runtime-corejs3
corejs2和corejs3還是有很大區(qū)別的。corejs2只轉(zhuǎn)換全局變量(Object)和靜態(tài)方法(Object.assign),并不轉(zhuǎn)換原型上的方法(Array.prototype.includes),corejs3會轉(zhuǎn)換原型上的方法。
注意transform-runtime這個(gè)插件添加的polyfill都是私有的,不會影響到全局環(huán)境,而且還是按需引入,非常nice。
小結(jié):
@babel/plugin-transform-runtime主要有三個(gè)作用:
- 當(dāng)使用 generators/async的時(shí)候自動引入 @babel/runtime/regenerator。
- 為新特性的API添加實(shí)現(xiàn)。
- 提取每個(gè)模塊內(nèi)聯(lián)的helper們問引用。
@babel/preset-env
除了上面說的 @babel/plugin-transform-runtime插件,還想記錄下 @babel/preset-env關(guān)于polyfill的改變。
這個(gè)preset在babel6的時(shí)候就承擔(dān)了很多功能,本文只記錄和polyfill相關(guān)的配置,useBuiltIns和 corejs。
useBuiltIns
在babel-preset-env的配置項(xiàng)中是一個(gè)boolean值,在@babel/preset-env的時(shí)候則擴(kuò)展了幾個(gè)選項(xiàng) "useage"和 "entry"。
默認(rèn)值是false,表示不會自動引入polyfills,并且不會處理 import “@babel/polyfill” 和 import “corejs”。
注:babel7.4會放棄 @babel/polyfill,所以建議直接使用 corejs。
entry
在入口文件有 import "core-js/stable"和 import "regenerator-runtime/runtime"。
會被自動分割為各個(gè)模塊的導(dǎo)入。
只能在入口引入一次,多次會報(bào)錯(cuò)。
usage
按需引入。同樣會造成全局污染。在我的理解中這個(gè)選項(xiàng)只是entry的一種增強(qiáng),不需要在入口手動引入一次,并且可以按照使用特性多少按需引入。
corejs
值:2, 3 或者 { version: 2 | 3, proposals: boolean }, 默認(rèn)是 2.
這是新加的一個(gè)配置項(xiàng)。該選項(xiàng)只會在 useBuiltIns選項(xiàng)為 usage或者 entry并且 @babel/preset-env正確導(dǎo)入對應(yīng)的corejs版本的情況下起作用。
默認(rèn)情況下只會注入穩(wěn)定功能的 ECMAScript 特性。有三個(gè)特性可以修改:
- 當(dāng)時(shí)用配置 useBuiltIns: "entry"可以直接導(dǎo)入提案 import "core-js/proposals/string-replace-all"
- 當(dāng)時(shí)用 useBuiltIns: usage 的時(shí)候又有兩個(gè)可選:
- 將shippedProposals(@babel/preset-env的另一個(gè)配置項(xiàng))選項(xiàng)設(shè)置為true。這將啟用已在瀏覽器中提供一段時(shí)間的提議的polyfill和轉(zhuǎn)換。
- 使用 corejs: {version:3,proposal:true}。這樣可以實(shí)現(xiàn)對core-js支持的每個(gè)提案的填充。
babel6
據(jù)我所知,在babel6中使用polyfill有四種方法:
直接引入(影響全局,一勞永逸)
在入口文件中 import 'babel-polyfill' / require('babel-polyfill')。使用webpack的話也可以在entry中添加 entry: ['babel-polyfill', 'src/index.js']。
優(yōu)點(diǎn):
一次引入,全局使用。
會轉(zhuǎn)換實(shí)例方法和靜態(tài)方法,比較全面。
缺點(diǎn):
影響全局作用域。
打出來的包比較大,不管用沒用到都打進(jìn)去了。
使用場景:
開發(fā)業(yè)務(wù)項(xiàng)目,比較全面,不會漏了從而出問題,比如Object.assign這樣的方法在ios8上面還是需要polyfill的。
在babel-runtime中單獨(dú)引入
和直接在入口引入polyfill不同,該插件引入的polyfill是模塊私有的。
對于需要的polyfill需要手動引入,import Promise from 'babel-runtime/core-js/promise'
優(yōu)點(diǎn):
該模塊私有,不會影響到全局作用域。
打出來的包因?yàn)榘葱枰氚粫艽蟆?/p>
缺點(diǎn):
因?yàn)椴挥绊懭肿饔糜?#xff0c;所以不會轉(zhuǎn)實(shí)例和靜態(tài)方法這樣的API。
手動引入所需,搞不好會漏掉。
使用場景:
開發(fā)庫,框架之類可以使用,因?yàn)閯e人用你的東西然后不知情的情況下你改了別人的全局環(huán)境,然后出錯(cuò)了就尷尬了。
使用babel-plugin-transform-runtime按需引入
這個(gè)插件可不簡單,有好幾個(gè)功能:
優(yōu)點(diǎn):
該模塊私有,不會影響到全局作用域。
打出來的包因?yàn)榘葱枰氚粫艽蟆?br /> 自動按需引入,不需要手動,防止遺漏。
提取helper,大大減少冗余代碼。
缺點(diǎn):
因?yàn)椴挥绊懭肿饔糜?#xff0c;所以不會轉(zhuǎn)實(shí)例和靜態(tài)方法這樣的API。
使用場景:
同babel-runtime。
注:該插件依賴babel-runtime。
在babel-preset-env中設(shè)置配置項(xiàng)
useBuiltIns 選項(xiàng)是為了分割入口的 import 'babel-polyfill' / require(babel-polyfill)成按環(huán)境引入polyfill。該方式同第一中引入polyfill的方式,但是會按照配置的環(huán)境去按需引入,稍微好點(diǎn)。
小結(jié):
1. babel6的核心有 babel-core babel-cli babel-node babel-register babel-polyfill,這些在babel7會有所修改。
2. polyfill 是依賴core-js的
3. babel7.4放棄了@babel/polyfill直接依賴core-js@2或者3。
babel-plugin-transform-runtime的配置項(xiàng)
{"helpers": false, // defaults to true"polyfill": false, // defaults to true"regenerator": true, // defaults to true"moduleName": "babel-runtime" // defaults to "babel-runtime" }對于polyfill的自動處理和helper的提取都是依賴babel-runtime完成的,所以該插件依賴babel-runtime。
polyfill例子
input:
var promise = new Promise;output:
var _promise = require("babel-runtime/core-js/promise"); // 注意這里,根本是從core-js里面引入的var _promise2 = _interopRequireDefault(_promise);function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var promise = new _promise2.default();helper的例子:
input:
class Person {}usually turns into:
"use strict";// 這就是helper函數(shù),每個(gè)模塊都會被實(shí)現(xiàn)一遍,十分浪費(fèi),冗余。 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }var Person = function Person() {_classCallCheck(this, Person); };通過runtime轉(zhuǎn)一下:
"use strict";var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); // 從runtime中引入,沒有再實(shí)現(xiàn)一遍var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var Person = function Person() {(0, _classCallCheck3.default)(this, Person); };generator同樣是 require("babel-runtime/regenerator");引入的。
參考
babel官網(wǎng)@babel/plugin-transform-runtime
npm->babel-plugin-transform-runtime
babel到底該如何配置?
babel手冊
Babel是一個(gè)JavaScript編譯器
babel7簡單升級
總結(jié)
以上是生活随笔為你收集整理的babel6和babel7中关于polyfill和preset-env和babel-plugin-transform-runtime等总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在React中获取数据
- 下一篇: 记录一次cookie导致登录失败的惨案