Babel配置傻傻看不懂?

前沿:文章起源在於,朋友跟樹醬說在解決項目兼容IE11瀏覽器過程當中,遇到「眼花繚亂」的babel配置和插件等,傻傻分不清配置間的區別、以及不瞭解如何引用babel插件才能讓性能更佳,若是你也有這方面的疑慮,這篇文章可能適合你

1.babel

babel是個什麼玩意? Babel本質上是一個編輯器,也就是個「翻譯官」的角色,好比樹醬聽不懂西班牙語,須要別人幫我翻譯成爲中文,我才曉得。那麼Babel就是幫助瀏覽器翻譯的,讓web應用可以運行舊版本的瀏覽器中,好比IE11瀏覽器不支持Promise等ES6語法,那這個時候在IE11打開你寫的web應用,應用就沒法正常運行,這時候就須要Babel來「翻譯」成爲IE11能讀懂的

1.1 Babel是怎麼工做的?

本質上單獨靠Babel是沒法完成「翻譯」,好比官網的例子 const babel = code => code;不借助Babel插件的前提,輸出是不會把箭頭函數「翻譯」的,若是想完成就須要用到插件,更多概念點點擊 官方文檔

Babel工做原理本質上就是三個步驟:解析、轉換、輸出,以下👇所示,html

1.2 AST 是什麼玩意?

👨‍🎓 啊斌同窗: 上面說到的抽象語法樹AST又是什麼玩意?

答:咱們上文提到,Babel在解析是時候會經過將code轉換爲AST抽象語法樹,本質上是代碼語法結構的一種抽象表示,經過以樹🌲形的結構形式表現出它的語法結構,抽象在於它的語言形態不會體如今原始代碼code中前端

下面介紹下在前端項目開發中一些AST的應用場景:vue

  • Vue模版解析: 咱們平時寫的.vue文件經過vue-template-compiler解析,.vue文件處理爲一個AST
  • Babel的「翻譯」 : 如將ES6轉換爲ES5過程當中轉爲AST
  • webpack的插件UglifyJSuglifyjs-webpack-plugin用來壓縮資源,uglifyjs會遇到須要解析es6語法,這個過程當中本質上也是藉助babel-loader

你能夠安裝經過本地安裝babel-cli作個驗證,經過babel-cli編譯js文件,玩玩「翻譯」webpack

🌲推薦閱讀:git

1.3 開發本身的babel插件須要瞭解什麼?

👨‍🎓 啊可同窗: 樹醬,我想本身使用AST開發一個babel插件須要使用到哪些東西呢?

答:咱們上一節中提到babel不借助「外援」的話,本身是沒法完成翻譯,而一個完整的「翻譯」的過程是須要走完解析、轉換、輸出才能完成整個閉環,而這其中的每一個環節都須要藉助babel如下這些APIes6

  • @babel/parser: babel解析器將源代碼code解析成 AST
  • @babel/generator: 將AST解碼生成js代碼 new Code
  • @babel/traverse : 用來遍歷AST樹,能夠用來改造AST~,如替換或添加AST原始節點
  • @babel/core:包括了整個babel工做流

下面是一個簡單「翻譯」的demo~github

👦:啊寬同窗:你不是說 @babel/parser是也將源代碼code解析成 AST嗎?爲啥 @babel/core也是?

答:@babel/core包含的是整個babel工做流,在開發插件的過程當中,若是每一個API都單獨去引入豈不是矇蔽了來吧~因而就有了@babel/core插件,顧名思義就是核心插件,他將底層的插件進行封裝(包含了parser、generator等),提升原有的插件開發效率,簡化過程,好一個「🍟肯德基全家桶」web

🌲推薦閱讀:vue-cli

1.4 Babel插件相關

講完Babel的基本使用,接下來聊聊插件,上文提到單獨靠babel是「難成大器」的,須要插件的輔助才能實現霸業,那插件是怎麼搞的呢?

經過第一節的學習咱們知道完成第一步驟解析完AST後,接下來是進入轉換,插件在這個階段就起到關鍵做用了。npm

1.4.1 插件的使用

告訴Babel該作什麼以前,咱們須要建立一個配置文件.babelrc或者babel.config.js文件

若是我想把es2015的語法轉化爲es5 及支持es2020的鏈式寫法,我能夠這樣寫

上圖所示👆,咱們能夠看到咱們配置兩個東西 presentplugin

👨‍🎓 啊可同窗:babel不是隻須要plugin來幫忙翻譯嗎,這個present又是什麼玩意?

答:presets是預設,舉個例子:有一天樹醬要去肯德基買雞翅、薯條、可樂、漢堡。而後我發現有個套餐A包含了(薯條、可樂、漢堡),那這個present就至關於套餐A,它包含了一些插件集合,一個大套餐,這樣我就只須要一個套餐A+雞翅就搞定了,不用配置不少插件。

就比如上面的es2015「套餐」,其實就是Babel團隊將同屬ES2015相關的不少個plugins集合到babel-preset-es2015一個preset中去

👧 啊琪同窗:@babel/preset-env這個是什麼?我看不少babel的配置都有

答:@babel/preset-env這個是一個present預設,換句話說就是「豪華大禮包」,包括一系列插件的集合,包含了咱們經常使用的es2015,es2016, es2017等最新的語法轉化插件,容許咱們使用最新的js語法,好比 let,const,箭頭函數等等,但不包括stage-x階段的插件。換句話說,他包含了咱們上文提到了es2015,是個「全家桶」了,而不只是個套餐了。

1.4.2 自定義 present

👦 啊斌同窗:樹醬,那我是否是能夠本身搞一個預設present?

答: 能夠的,可是你能夠以 babel-preset-* 的命名規範來建立一個新項目,而後建立一個packjson並安裝好定影的依賴和一個index.js 文件用於導出 .babelrc,最終發佈到npm中,以下所示

1.4.3 關於 polyfill

好比咱們在開發中使用,會使用到一些es6的新特徵好比 Array.from等,但不是全部的 JavaScript 環境都支持 Array.from,這個時候咱們可使用 Polyfill(代碼填充,也可譯做兼容性補丁)的「黑科技」,由於babel只轉換新的js語法,如箭頭函數等,但不轉換新的API,好比Symbol、Promise等全局對象,這時候須要藉助 @babel/polyfill,把es的新特性都裝進來,使用步驟以下
  • npm 安裝 : npm install --save @babel/polyfill
  • 文件頂部導入 polyfill: import @babel/polyfilll

🙅‍♂️:缺點:全局引入整個 polyfill包,如promise會被全局引入,污染全局環境,因此不建議使用,那有沒有更好的方式?能夠直接使用@babel/preset-env並修改配置,由於@babel/preset-env包含了@babel/polyfill插件,看下一節

1.4.4 如何經過修改@babel/preset-env配置優化

完成上面的配置,而後用Babel編譯代碼,咱們會發現有時候打出的包體積很大,由於@babel/polyfill有些會被全局引用,那你要弄清楚@babel/preset-env的配置

@babel/preset-env 中與 @babel/polyfill 的相關參數有兩個以下:

  • targets: 支持的目標瀏覽器的列表
  • useBuiltIns: 參數有 「entry」、」usage」、false 三個值。默認值是false,此參數決定了babel打包時如何處理@babel/polyfilll 語句

主要聊聊關於useBuiltIns的不一樣配置以下:

  • entry: 去掉目標瀏覽器已支持的polyfilll 模塊,將瀏覽器不支持的都引入對應的polyfilll 模塊。
  • usage: 打包時會自動根據實際代碼的使用狀況,結合 targets 引入代碼裏實際用到部分 polyfilll模塊
  • false: 不會自動引入 polyfilll 模塊,對polyfilll模塊屏蔽

🌲建議:使用 useBuiltIns: usage來根據目標瀏覽器的支持狀況,按需引入用到的 polyfill 文件,這樣打包體積也不會過大

1.4.5 webpack打包如何使用babel?

對於 @babel/core@babel/preset-env@babel/polyfill等這些插件,當咱們在使用webpack進行打包的時候,如何讓webpack知道按這些規則去編譯js。這時就須要 babel-loader了,它至關於一箇中間橋樑,經過調用babel/core中的API來告知webpack要如何處理。

1.4.6 開發工具庫,涉及到babel使用怎麼避免污染環境?

👦 啊斌同窗:我開發了一個工具庫,也使用了babel,若是引用polyfill,如何避免使用致使的污染環境?

答:在開發工具庫或者組件庫時,就不能再使用babel-polyfill了,不然可能會形成全局污染,可使用@babel/runtime。它不會污染你的原有的方法。遇到須要轉換的方法它會另起一個名字,不然會直接影響使用庫的業務代碼,使用@babel/runtime主要在於

  • 能夠減少庫和工具包的體積,規避babel編譯的工具函數在每一個模塊裏都重複出現的狀況
  • 在沒有使用 @babel/runtime 以前,庫和工具包通常不會直接引入 polyfill。不然像 Promise 這樣的全局對象會污染全局命名空間,這就要求庫的使用者本身提供 polyfill。這些 polyfill 通常在庫和工具的使用說明中會提到,好比不少庫都會有要求提供 es5 的 polyfill。在使用 babel-runtime 後,庫和工具只要在 package.json 中增長依賴 babel-runtime,交給 babel-runtime 去引入 polyfill就能夠了

如何使用 @babel/runtime

  • 1.npm安裝
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
  • 2.配置

1.5 關於babel容易混淆的點

1.5.1 babel-core和@babel/core 區別

👦:啊呆同窗:babel-core和@babel/core是什麼區別?

答;@babel是在babel7中版本提出來的,就相似於 vue-cli 升級後使用@vue/cli同樣的道理,因此babel7之後的版本都是使用 @babel 開頭聲明做用域,

相關文章
相關標籤/搜索