babel6和babel7中关于polyfill和preset-env和babel-plugin-transform-runtime等总结
記錄自己零散的收獲,隨筆。
一些基礎
babel的作用是轉換JS新的特性代碼為大部分瀏覽器能運行的代碼。
babel轉碼又分為兩部分,一個是語法轉換,一個是API轉換。
對于API的轉換又分為兩部分,一個是全局API例如Promise,Set,Map還有靜態方法Object.assign,另一個是實例方法例如Array.prototype.includes。對于實例方法core-js@2是轉換不了的,只有core-js@3才會轉換。
babel代碼轉換依賴plugin,沒有plugin的情況下babel做的事情只是 code => code。
plugin 有很多,一個個導入又特別麻煩,這時候我們又知道了preset。
preset是很多plugin的集合,配置如下:
.babelrc文件
{"presets": ["env"] }如果preset-env是有配置項的:
{"presets": [["env",{// 這里就是配置項}]] }可以觀察出如果某個preset需要配置可以將字符串換成一個數組,第一項是preset的name,第二項就是options。plugin同preset。
注:preset是從右往左執行,plugin是從左往右執行,并且plugin先于preset執行。
babel6到babel7的升級是具有破壞性的,主要總結下polyfill的用法和在babel6和babel7中的不同。
babel-polyfill
上面說到babel主要做兩件事,一個是轉換語法,一個是兼容新的API。
babel-polyfill 的作用是兼容新的API。
babel7
babel7進行了較大的改動,廢棄了 stage-x的preset,還增加了命名空間區分官方插件和非官方插件,@babel/core,@babel/cli等。
建議使用@babel/preset-env 。
@babel/plugin-transform-runtime
該插件的引入主要有兩個作用
在babel7中,原先的插件babel-plugin-transform-runtime也做了修改 -> @babel/plugin-transform-runtime。并且在功能上也變強大了。
移除了polyfill的配置項添,加了corejs配置項。
@babel/plugin-transform-runtime的默認配合如下:
{plugins: [["@babel/plugin-transform-runtime", {"absoluteRuntime": false, // 不是很清除干啥的"corejs": false, // 下面詳解"helpers": true, // 助手函數是否提取,同babel-plugin-transform"regenerator": true, // 同babel-plugin-transform"useESModules": false}]] }對于配置項 corejs: false | 2 | 3。
false 依賴 @babel/runtime,是默認選項,認為需要填充的API以被填充,所以不對API作polyfill(對于@babel/runtime的依賴是提取的helper的依賴)。
2 依賴@babel/runtime-corejs2
3 依賴@babel/runtime-corejs3
corejs2和corejs3還是有很大區別的。corejs2只轉換全局變量(Object)和靜態方法(Object.assign),并不轉換原型上的方法(Array.prototype.includes),corejs3會轉換原型上的方法。
注意transform-runtime這個插件添加的polyfill都是私有的,不會影響到全局環境,而且還是按需引入,非常nice。
小結:
@babel/plugin-transform-runtime主要有三個作用:
- 當使用 generators/async的時候自動引入 @babel/runtime/regenerator。
- 為新特性的API添加實現。
- 提取每個模塊內聯的helper們問引用。
@babel/preset-env
除了上面說的 @babel/plugin-transform-runtime插件,還想記錄下 @babel/preset-env關于polyfill的改變。
這個preset在babel6的時候就承擔了很多功能,本文只記錄和polyfill相關的配置,useBuiltIns和 corejs。
useBuiltIns
在babel-preset-env的配置項中是一個boolean值,在@babel/preset-env的時候則擴展了幾個選項 "useage"和 "entry"。
默認值是false,表示不會自動引入polyfills,并且不會處理 import “@babel/polyfill” 和 import “corejs”。
注:babel7.4會放棄 @babel/polyfill,所以建議直接使用 corejs。
entry
在入口文件有 import "core-js/stable"和 import "regenerator-runtime/runtime"。
會被自動分割為各個模塊的導入。
只能在入口引入一次,多次會報錯。
usage
按需引入。同樣會造成全局污染。在我的理解中這個選項只是entry的一種增強,不需要在入口手動引入一次,并且可以按照使用特性多少按需引入。
corejs
值:2, 3 或者 { version: 2 | 3, proposals: boolean }, 默認是 2.
這是新加的一個配置項。該選項只會在 useBuiltIns選項為 usage或者 entry并且 @babel/preset-env正確導入對應的corejs版本的情況下起作用。
默認情況下只會注入穩定功能的 ECMAScript 特性。有三個特性可以修改:
- 當時用配置 useBuiltIns: "entry"可以直接導入提案 import "core-js/proposals/string-replace-all"
- 當時用 useBuiltIns: usage 的時候又有兩個可選:
- 將shippedProposals(@babel/preset-env的另一個配置項)選項設置為true。這將啟用已在瀏覽器中提供一段時間的提議的polyfill和轉換。
- 使用 corejs: {version:3,proposal:true}。這樣可以實現對core-js支持的每個提案的填充。
babel6
據我所知,在babel6中使用polyfill有四種方法:
直接引入(影響全局,一勞永逸)
在入口文件中 import 'babel-polyfill' / require('babel-polyfill')。使用webpack的話也可以在entry中添加 entry: ['babel-polyfill', 'src/index.js']。
優點:
一次引入,全局使用。
會轉換實例方法和靜態方法,比較全面。
缺點:
影響全局作用域。
打出來的包比較大,不管用沒用到都打進去了。
使用場景:
開發業務項目,比較全面,不會漏了從而出問題,比如Object.assign這樣的方法在ios8上面還是需要polyfill的。
在babel-runtime中單獨引入
和直接在入口引入polyfill不同,該插件引入的polyfill是模塊私有的。
對于需要的polyfill需要手動引入,import Promise from 'babel-runtime/core-js/promise'
優點:
該模塊私有,不會影響到全局作用域。
打出來的包因為按需引入包不會很大。
缺點:
因為不影響全局作用域,所以不會轉實例和靜態方法這樣的API。
手動引入所需,搞不好會漏掉。
使用場景:
開發庫,框架之類可以使用,因為別人用你的東西然后不知情的情況下你改了別人的全局環境,然后出錯了就尷尬了。
使用babel-plugin-transform-runtime按需引入
這個插件可不簡單,有好幾個功能:
優點:
該模塊私有,不會影響到全局作用域。
打出來的包因為按需引入包不會很大。
自動按需引入,不需要手動,防止遺漏。
提取helper,大大減少冗余代碼。
缺點:
因為不影響全局作用域,所以不會轉實例和靜態方法這樣的API。
使用場景:
同babel-runtime。
注:該插件依賴babel-runtime。
在babel-preset-env中設置配置項
useBuiltIns 選項是為了分割入口的 import 'babel-polyfill' / require(babel-polyfill)成按環境引入polyfill。該方式同第一中引入polyfill的方式,但是會按照配置的環境去按需引入,稍微好點。
小結:
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的配置項
{"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函數,每個模塊都會被實現一遍,十分浪費,冗余。 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轉一下:
"use strict";var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); // 從runtime中引入,沒有再實現一遍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官網@babel/plugin-transform-runtime
npm->babel-plugin-transform-runtime
babel到底該如何配置?
babel手冊
Babel是一個JavaScript編譯器
babel7簡單升級
總結
以上是生活随笔為你收集整理的babel6和babel7中关于polyfill和preset-env和babel-plugin-transform-runtime等总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在React中获取数据
- 下一篇: 记录一次cookie导致登录失败的惨案