什么是 BABEL
Babel 官方文檔: https://babeljs.io/
我們知道各個瀏覽器對 JavaScript 版本的支持各不相同糊啡,有很多優(yōu)秀的新語法都不能直接在瀏覽器中運行梭依。為了解決這個“溝通不暢”的問題,所以就有了 Babel,Babel 的出現(xiàn)使得我們可以無須顧忌的去使用 ES6+ 的語法姜性。
Babel is a JavaScript compiler.
這也是為何我們必須使用 ES6+ 語法的前提條件儡炼。
BABEL 如何編譯
先看下面這張圖:你會發(fā)現(xiàn) ES6 的語法確實被編譯成瀏覽器可以識別的版本了楣责,你是不是也在問這是怎么做到的呢?
BABEL 編譯的階段
babel 總共分為三個階段:解析驻龟,轉(zhuǎn)換缸匪,生成翁狐。
我們需要知道現(xiàn)在 babel 本身是不具備這種轉(zhuǎn)化功能,提供這些轉(zhuǎn)化功能的是一個個 plugin凌蔬。所以我們沒有配置任何 plugin 的時候露懒,經(jīng)過 Babel 輸出的代碼是沒有改變的。
PLUGIN —— TRANSFORM 的載體
Babel 自 6.0 起砂心,就不再對代碼進行轉(zhuǎn)換⌒复剩現(xiàn)在只負責(zé)圖中的 parse 和 generate 流程,轉(zhuǎn)換代碼的 transform 過程全都交給插件去做辩诞。
例子:
// 模板字面量
const name = '小生方勤';
let hello = `hello ${name}`;
上面是一個簡單的模板字面量的例子坎弯,我們清楚這個是 ES6 的新特性,在不支持 ES6 的運行平臺這段代碼是會報錯的躁倒,所以我們需要 Babel 來將其編譯成 ES5 的代碼荞怒。
所以我們需要如下來配置 babel:
// .babelrc 文件
{
"plugins": [
"transform-es2015-template-literals" // 轉(zhuǎn)譯模版字符串的 plugins
],
"presets": ["env", "stage-2"]
}
preset(即一組預(yù)先設(shè)定的插件)
preset: babel 插件集合的預(yù)設(shè),包含某些插件 plugin秧秉。顯然像上面那樣一個一個配置插件會非常的麻煩褐桌,為了方便,babel 為我們提供了一個配置項叫做 persets(預(yù)設(shè))象迎。
當(dāng)前 babel 推薦使用 babel-preset-env 替代 babel-preset-es201X ,env 的支持范圍更廣荧嵌,包含es201X 的所有語法編譯,并且它可以根據(jù)項目運行平臺的支持情況自行選擇編譯版本砾淌。
PLUGINS 與 PRESETS 同時存在的執(zhí)行順序
先執(zhí)行 plugins 的配置項,再執(zhí)行 Preset 的配置項啦撮;
plugins 配置項,按照聲明順序執(zhí)行汪厨;
Preset 配置項赃春,按照聲明逆序執(zhí)行。
列入以下代碼的執(zhí)行順序為:
transform-es2015-template-literals
stage-2
env
// .babelrc 文件
{
"plugins": [
"transform-es2015-template-literals", // 轉(zhuǎn)譯模版字符串的 plugins
],
"presets": [
["env", {
// 是否自動引入 polyfill劫乱,開啟此選項必須保證已經(jīng)安裝了 babel-polyfill
// “usage” | “entry” | false, defaults to false.
"useBuiltIns": "usage"
}], "stage-2"]
}
這里講一講 useBuiltIns 配置
我們可能在全局引入 babel-polyfill织中,這樣打包后的整個文件體積必然是會變大的。
但是通過設(shè)置 "useBuiltIns":"usage"
能夠把 babel-polyfill 中你需要用到的部分提取出來衷戈,不需要的去除狭吼。
useBuiltIns 參數(shù)說明:
false: 不對 polyfills 做任何操作
entry: 根據(jù) target 中瀏覽器版本的支持,將 polyfills 拆分引入殖妇,僅引入有瀏覽器不支持的 polyfill
usage(新):檢測代碼中 ES6/7/8 等的使用情況刁笙,僅僅加載代碼中用到的 polyfills
BABEL 相關(guān)模塊簡要說明
了解過 Babel 的同學(xué),是否也覺得的模塊有點多呢?我開始學(xué)習(xí)的時候就有這種感覺疲吸。其實每個模塊是各司其職的座每。
BABEL-CORE(核心)
這個模塊是最能顧名思義的了,即 babel 的核心模塊摘悴。babel 的核心 api 都在這個模塊中尺栖。也就是這個模塊會把我們寫的 js 代碼抽象成 AST 樹;然后再將 plugins 轉(zhuǎn)譯好的內(nèi)容解析為 js 代碼烦租。
具體怎么工作的這里就不詳細說了,因為我也不知道除盏。
BABEL-CLI
babel-cli 官方文檔:https://babeljs.io/docs/en/babel-cli/
babel-cli 是一個通過命令行對 js 文件進行轉(zhuǎn)換的工具叉橱。
當(dāng)然我們一般不會使用到這個模塊,因為一般我們都不會手動去做這個工作者蠕,這個工作基本都集成到模塊化管理工具中去了窃祝,比如 webpack、Rollup 等踱侣。
簡單使用(需要先安裝 babel-cli):
babel test.js -o compiled.js
BABEL-NODE
babel-node 是 babel-cli 的一部分粪小,所以它在安裝 babel-cli 的時候也同時安裝了。
它使 ES6+ 可以直接運行在 node 環(huán)境中抡句。
BABEL-POLYFILL(內(nèi)部集成了 CORE-JS 和 REGENERATOR)
babel 對一些新的 API 是無法轉(zhuǎn)換探膊,比如 Generator、Set待榔、Proxy逞壁、Promise 等全局對象,以及新增的一些方法:includes锐锣、Array.form 等腌闯。所以這個時候就需要一些工具來為瀏覽器做這個兼容。
官網(wǎng)的定義:babel-polyfill 是為了模擬一個完整的 ES6+ 環(huán)境雕憔,旨在用于應(yīng)用程序而不是庫/工具姿骏。
babel-polyfill 主要有兩個缺點:
使用 babel-polyfill 會導(dǎo)致打出來的包非常大,很多其實沒有用到斤彼,對資源來說是一種浪費分瘦。
babel-polyfill 可能會污染全局變量,給很多類的原型鏈上都作了修改畅卓,這就有不可控的因素存在擅腰。
因為上面兩個問題,所以在 Babel7 中增加了 babel-preset-env翁潘,我們設(shè)置 "useBuiltIns":"usage"
這個參數(shù)值就可以實現(xiàn)按需加載 babel-polyfill 啦趁冈。
BABEL-RUNTIME & BABEL-PLUGIN-TRANSFORM-RUNTIME
在使用 Babel6 的時候, .babelrc 文件中會使用 babel-plugin-transform-runtime,而 package.json 中的 dependencies 同時包含了 babel-runtime渗勘,因為在使用 babel-plugin-transform-runtime 的時候必須把 babel-runtime 當(dāng)做依賴沐绒。
.babelrc 配置:
{
"presets": [
["env"]
],
"plugins": [
["transform-runtime", {
"helpers": false, // defaults to true
"polyfill": false, // defaults to true
"regenerator": true, // defaults to true
"moduleName": "babel-runtime" // defaults to "babel-runtime"
}]
]
}
我們在啟用插件 babel-plugin-transform-runtime 后,Babel 就會使用 babel-runtime 下的工具函數(shù)旺坠,將一些瀏覽器不能支持的特性重寫乔遮,然后在項目中使用。
babel-runtime 內(nèi)部也集成了 core-js取刃、 regenerator蹋肮、helpers 等
由于采用了沙盒機制,這種做法不會污染全局變量璧疗,也不會去修改內(nèi)建類的原型坯辩,所以會有重復(fù)引用的問題。
現(xiàn)在最好的實踐應(yīng)該是在 babel-preset-env 設(shè)置 "useBuiltIns": "usage"崩侠,按需引入 polyfill漆魔。
三種方案對比
方案 | 優(yōu)點 | 缺點 |
---|---|---|
@babel/runtime & @babel/plugin-transform-runtime | 按需引入, 打包體積小 | 不能兼容實例方法 |
@babel/polyfill | 完整模擬 ES2015+ 環(huán)境 | 打包體積過大, 污染全局對象和內(nèi)置的對象原型 |
@babel/preset-env | 按需引入, 可配置性高 | 小生不知 -_- |
BABEL7 的一些變化
PRESET 的變更:
淘汰 es201x,刪除 stage-x却音,推薦 env
如果你還在使用 es201x改抡,官方建議使用 env 進行替換。淘汰并不是刪除系瓢,只是不推薦使用阿纤。
但 stage-x 是直接被刪了,也就是說在 babel7 中使用 es201X 是會報錯的八拱。
包名稱變化
babel 7 的一個重大變化阵赠,把所有 babel-* 重命名為 @babel/*,
例如:
babel-cli —> @babel/cli肌稻。
babel-preset-env —> @babel/preset-env
低版本 NODE 不再支持
babel 7.0 開始不再支持 nodejs 0.10, 0.12, 4, 5 這四個版本清蚀,相當(dāng)于要求 nodejs >= 6爹耗。
還有一些包從其他包獨立出來的變化等等