一天快速瞭解Babel

在作項目中一直使用的是腳手架搭建的環境,一直沒有仔細的去了解 babel 這一工具,這週末抽出一天時間經過官網還有各類博客文章算是瞭解了一些內容,起碼能夠在項目中本身完成 .babelrc 的配置了。css

這篇文章就是把本身的理解和找到的優秀文章的內容作一融合和整理,理解有誤的地方還請你們批評指正~html

由於主要是面對項目,因此本文內容主要仍是圍繞 .babelrc 展開,與babel 相關的其餘工具無關。vue

Babel 是什麼?

Babel is a toolchain that is mainly used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in old browsers or environments.

因爲瀏覽器對 ECMAScript 的支持各有差別,所以 Babel 是一個用來將 ES6 版本以上代碼轉爲 ES5 版本代碼的工具,從而使得編寫的代碼能夠在指定的環境下運行。node

.babelrc 配置文件

在項目中咱們使用 Babel 作轉碼通常使用配置文件的形式。Babel 的配置文件名爲 .babelrc 而且一般放在項目根路徑下,其格式大體以下:webpack

{
  "env": {
    "production": {
      "presets": [],    // 轉碼規則
      "plugins": [],    // 插件
      "ignore": ["node_modules/"]    // 轉碼時候忽略的文件
    }
  }
}

這裏的 env 的值取得是項目中的 process.env.BABEL_ENV 若是該值找不到,則取 process.env.NODE_ENV 最後若是該值還找不到,則設爲 developmentgit

處理順序

  1. plugins 優先於 presets
  2. plugins 從數組第一個到最後一個進行編譯
  3. presets 從數組最後一個到第一個進行編譯 ,這個目的主要爲了向後降級

presets

presets 用於設置轉碼的規則,經常使用的 presetsenvstage-xgithub

關於 env 後文會提到,先來看看 stage-xweb

stage-x 是新特性歸入標準所通過的幾個階段, x 值越小,表示階段越靠後,靠後的階段包含前面的全部內容,即 stage-0 包含 stage-1/2/3 的全部內容

babelstage

上圖是 stage-2index.js 文件,能夠看到其中直接引用了 stage-3 的全部特性。vue-cli

實際上來講,presets 就是 plugins 的集合,若是沒有 preset 也是能夠完成代碼轉換工做的,以下。npm

{
  "plugins": [
    "check-es2015-constants",
    "es2015-arrow-functions"
  ]
}

可是因爲這麼配置過於繁瑣,所以 Babel 把一些屬於同一標準的 transform-plugins 劃歸到一個 presets 中,這樣有了 presets 就不用再一個一個地導入 transform-plugins 了。

babel-polyfill & babel-runtime

Babel 默認只轉換 JS 語法,而不轉換新的 API ,新標準中的全局對象和定義在這些全局對象上的方法都不會轉碼,這些 API 不少,具體參考 definitions.js

這就致使了 babel-polyfillbabel-runtime 的產生

babel-polyfill

  1. 把全部的 polyfill 一次性所有引入,無論你在項目中是否真正用到
  2. 污染全局對象,可能引起衝突。若是你開發的是一個應用項目,那麼這一點能夠暫時忽略,可是若是你開發的是一款插件或者別人未來引入的包,那麼頗有可能會給使用者帶來不便
  3. 由於須要在本身的代碼以前運行這些 polyfill 因此該包應該被添加到 dependency
  4. webpack 結合使用時候須要放在 entry 數組中 entry: ["babel-polyfill", "app.js"]

babel-runtime

babel-polyfill 的一次性引入不一樣,babel-runtime 支持本身手動引入 helper 函數,來完成對某一 API 的轉碼。它更像是一個個分散的 polyfill 模塊。

顯而易見 babel-runtime 的缺點之一就是每次使用 API 的時候,都須要咱們進行手動引入,很麻煩;此外,在代碼中直接引入 helper 函數,會致使打包的文件中出現不少重複 helper 代碼。所以如今實際工做中會使用 babel-runtime + babel-plugin-transform-runtime 的形式

babel-plugin-transform-runtime

這個包能夠幫咱們完成 babel-runtimehelper 函數的自動引入,而且它還作了公用方法的抽離,你引入的函數都是引用自一個地方,就避免了重複的代碼

該包依賴 babel-runtime ,這也是爲何咱們在使用 webpack 配置 babel 的時候,只須要安裝 babel-plugin-transform-runtime 的緣由,
devDependencies 裏只看見了 babel-plugin-transform-runtime

該插件主要作了三件事:

  1. 當你使用 generators/async 方法、函數時自動調用 babel-runtime/regenerator
  2. 當你使用 ES6 的 Map 或者內置的東西時自動調用 babel-runtime/core-js
  3. 移除內聯 babel helpers 並替換使用 babel-runtime/helpers 來替換

優勢

  1. 不會污染全局變量
  2. 屢次使用只打包一次
  3. 依賴按需引入,無重複引入
  4. 適合編寫庫類型的代碼

缺點

  1. 不支持實例化的方法 'foobar'.includes('foo') 不能轉化

配置

通常直接默認就行,不須要對該插件進行配置
{
  "plugins": [
    ["transform-runtime", {
      "polyfill": true,       // 是否把新特性轉換爲非全局的 polyfill
      "helpers": true,        // 是否用模塊中的 helpers 替換內聯 helpers
      "regenerator": true,    // 是否把生成器函數轉換爲非全局的 polyfill
      "moduleName": "babel-runtime"  // 導入 helpers 的時候的模塊路徑
    }]
  ]
}

一次小測試

.babelrc

babelrctest

轉碼前的 a.js

babelrctestajs

轉碼後的 a-compiled.js

babelrctestacjs

能夠看到實例方法 "foo".includes('f') 並無被轉換

再來一個小測試

.babelrc

babelrctest2

轉碼前的 b.js

babelrctest2bjs

使用 babel 轉碼後,Set 轉碼成功,而且能夠看到在轉碼後的文件中,打印的並非原生的 Set ,而是 babel 爲咱們包裝的一個替代原生 Set 的模塊,避免了全局污染。

babelrctest2bcjs


當咱們把 .babelrc 中改成 polyfill: false 時,再次對 b.js 轉碼,轉碼後,語句沒有被處理。打印的就是原生的 Set ,污染了全局變量。

babelrctest2bncjs


若是須要對實例方法進行轉碼,能夠這麼來,固然你須要在 .babelrc 裏改成 polyfill: true ,否則沒有這個 polyfill 根本沒有這些方法。

轉碼前:

babelrctest3bjs

轉碼後:

babelrctest3bcjs

若是非要在不支持的環境下使用實例方法的話,就還得藉助 babel-polyfill 了(或者你本身實現一個)。不過好像目前瀏覽器端對這種諸如 includesrepeat 之類的方法支持的還不錯了。

babel-preset-env

Without any configuration options, babel-preset-env behaves exactly the same as babel-preset-latest (or babel-preset-es2015, babel-preset-es2016, and babel-preset-es2017 together).

首先官網上給了公式

沒有任何配置的 env = latest = es2015 + es2016 + es2017

babel-preset-env 因爲其靈活的配置和全面的功能,被官網推薦,同時也是目前應用很頻繁的 presets

配置項

targets

提供須要支持的環境信息,版本等,默認爲 {}

spec

經過犧牲轉換時間來支持該 preset 的更多規範兼容性,默認爲 false

loose

preset 中的插件開啓鬆散轉換

鬆散模式

優勢:轉換的代碼更加簡潔,沒有爲了接近 ES6 而添加的繁雜邏輯,文件更小,運行速度更快,兼容性更好

缺點:直接使用原生 ES6 可能會有問題

通常不推薦使用鬆散模式

簡單來講,鬆散模式轉換後的代碼很容易就能看懂,並且很像咱們平時寫的代碼,但這種不嚴謹的轉換可能會形成問題,因此在開發中是不推薦的。

感覺一下:

轉碼前:

babelloosesource

轉碼後(正常):

babelloosenormal

轉碼後(鬆散):

babellooseloose

modules

把 ES6 模塊語法轉爲另外一個模塊類型,默認 commonjs

如今的 webpack 4.x 已經把模塊統一的任務完成了,因此這裏就不須要 babel 來作了,因此在 vue-cli 這種用 webpack 打包的腳手架裏,你會看到 .babelrc 文件中有 module: false 這就是爲了防止與 webpack 衝突

include

指定一組老是包括的插件,當原生實現有問題,或存在不支持或支持很差的特性時候使用,默認爲 []

includeexclude 只工做於包含在 preset 裏有的插件中,若是要使用 preset 裏不包含的插件,直接填在 .babelrcplugins

exclude

指定一組老是不包括的插件,默認爲 []

useBuiltIns

默認爲 false
會啓用一個插件來根據使用狀況去按需加載 polyfill 來替代 import "babel-polyfill" 語句

其餘 Babel 工具

全部的工具建議都在項目中安裝,而不是採用全局安裝
  1. babel-cli 用於命令行轉碼
  2. babel-node 跟隨 babel-cli 安裝,可直接運行 ES6 代碼,由於採用這種方式是實時轉碼的,轉碼的全部工具都存在內存中,產生大量資源消耗所以只適合在開發中使用
  3. babel-register 改寫 require 命令,每次使用 require 加載 js 文件時候,就會先轉碼,由於是實時轉碼,只適合在開發環境使用
  4. babel-core 提供 Babel 的 API,以後能夠採用編程方式使用 Babel

參考連接

  1. Babel · The compiler for next generation JavaScript
  2. 對babel-transform-runtime,babel-polyfill的一些理解
  3. Babel 入門教程 - 阮一峯的網絡日誌
  4. babel-polyfill的幾種使用方式
  5. Babel筆記 - Tony’s Blog
  6. Babel的使用
  7. Babel 6 鬆散模式
相關文章
相關標籤/搜索