babel polyfill 的一些理解
前言
為了支援業務中少量的es6+的高階特性,最近在研究了一下babel的墊片,現將此整理為文字,如下。
babel 和 babel ployfill 的關係
1、先來理解下 babel 到底是做什麼的?
簡單來講,babel解決語法層面的問題。用於將ES6+的高階語法轉為ES5。
2、babel polyfill 又是做什麼的?
如果要解決API層面的問題,需要使用墊片。比如常見的有babel-polyfill、babel-runtime和babel-plugin-transform-runtime。
理清了他們之間的關係,那麼再正式來講講有關polyfill的二三事。
polyfill 種類
babel polyfill 有三種
* babel-polyfill
* babel-runtime
* babel-plugin-transform-runtime
babel-polyfill
babel-polyfill通過向全域性物件和內建物件的prototype上新增方法來實現的。所以這會造成全域性空間汙染。
babel-polyfill使用的兩種方式
1、webpack.config.js中:
配置webpack.config.js裡的entry設定為entry: ['babel-polyfill',path.join(__dirname, 'index.js')]
2、業務 js 中:
在webpack.config.js配置的主入口index.js檔案的最頂層鍵入
import'babel-polyfill'
兩者打印出來的大小都是一樣的,打包後大小是280KB,如果沒有使用babel-polyfill,大小是3.43kb。兩則相差大概81.6倍。原因是webpack把babel-polyfill整體全部都打包進去了。而babel-polyfill肯定也實現了所有ES6新API的墊片,檔案一定不會小。
那麼有沒有一種辦法,根據實際程式碼中用到的ES6新增API ,來使用對應的墊片,而不是全部載入進去呢?
是的,有的。那就是babel-runtime&babel-plugin-transform-runtime,他們可以實現按需載入。
babel-runtime
簡單說 babel-runtime 更像是一種按需載入的實現,比如你哪裡需要使用 Promise,只要在這個檔案頭部
importPromisefrom'babel-runtime/core-js/promise'
就行了。
不過如果你許多檔案都要使用 Promise,難道每個檔案都要import一下嗎?當然不是,Babel 官方已考慮這種情況,只需要使用babel-plugin-transform-runtime就可以解決手動import的苦惱了。
babel-plugin-transform-runtime
babel-plugin-transform-runtime裝了就不需要裝babel-runtime了,因為前者依賴後者。
總的來說,babel-plugin-transform-runtime就是可以在我們使用新 API 時自動 import babel-runtime 裡面的 polyfill,具體外掛做了以下三件事情:
- 當我們使用 async/await 時,自動引入 babel-runtime/regenerator
- 當我們使用 ES6 的靜態事件或內建物件時,自動引入 babel-runtime/core-js
- 移除內聯 babel helpers 並替換使用 babel-runtime/helpers 來替換
babel-plugin-transform-runtime優點:
- 不會汙染全域性變數
- 多次使用只會打包一次
- 依賴統一按需引入,無重複引入,無多餘引入
- 避免 babel 編譯的工具函式在每個模組裡重複出現,減小庫和工具包的體積
使用方式
在 .babelrc 中配置:
plugins:\["tranform-runtime"\]
打包後大小為17.4kb,比之前的280kb要小很多。
資源搜尋網站大全 https://www.renrenfan.com.cn
Plugin 外掛
1、官方 Presets
如果不想自己設定一堆外掛的話,官方有env,react,flow三個 Presets。即預安裝了 plugins 的配置。
presets 屬性告訴 Babel 要轉換的原始碼使用了哪些新的語法特性, presets 是一組 Plugins 的集合。如:
babel-preset-es2015: 可以將es6的程式碼編譯成es5
babel-preset-es2016: 可以將es7的程式碼編譯為es6
babel-preset-es2017: 可以將es8的程式碼編譯為es7
babel-preset-latest: 支援現有所有ECMAScript版本的新特性
當我們需要轉換es6語法時,可以在 .babelrc 的 plugins 中按需引入一下外掛,比如:check-es2015-constants、es2015-arrow-functions、es2015-block-scoped-functions等等幾十個不同作用的 plugin。.babelrc中配置項可能是如下方式:
{
"plugins": \[
"check-es2015-constants",
"es2015-arrow-functions",
"es2015-block-scoped-functions",
// ...
\]
}
但 Babel 團隊為了方便,將同屬 ES2015 的幾十個 Transform Plugins 集合到babel-preset-es2015一個 Preset 中,這樣我們只需要在.babelrc的 presets 加入 ES2015 一個配置就可以完成全部 ES2015 語法的支援了。.babelrc中配置如下:
{
"presets": \[
"es2015"
\]
}
2、Stage-X(試驗性 Presets)
這個比較好理解,就是為了支援 TC39 對於草案階段的 ES 最新特性而開發的 presets。
- Stage 0 - 草稿:只是一個設想可能是一個 Babel 外掛
- Stage 1 - 提案:值得去推進的東西
- Stage 2 - 草案:初始化規範
- Stage 3 - 候選:完整規範和初始化瀏覽器實現
- Stage 4 - 完成:會加入到下一版中
3、轉換外掛
官方和民間提供了很多的轉換外掛,用於指定對某一項 ES 高階特性進行轉換。
官方見:https://babeljs.io/docs/en/pl...
4、語法外掛
這種外掛可以讓Babel來解析特殊型別的語法。
{
"parserOpts": {
"plugins": \["jsx", "flow"\]
}
}
5、外掛開發
見文件:https://github.com/jamiebuild...
開發採用了 AST 抽象語法樹,類似於 Eslint 外掛開發。
export default function () {
return {
visitor: {
Identifier(path) {
const name = path.node.name;
// reverse the name: JavaScript -> tpircSavaJ
path.node.name = name.split("").reverse().join("");
}
}
};
}
webpack 中使用 babel 二三事
babel 用途是語法轉換,所以webpack 中需要用到babel-loader。而babel-core是 Babel 編譯器的核心,因此也就意味著如果我們需要使用babel-loader進行 es6 轉碼的話,我們首先需要安裝babel-core。
總結
使用場景建議:
- 開發應用建議使用babel-polyfill 會在全域性新增對應方法
- 開發框架建議 babel-plugin-transform-runtime 區域性變數 不會汙染全域性,區域性使用es6的函式或方法