在作項目中一直使用的是腳手架搭建的環境,一直沒有仔細的去了解 babel
這一工具,這週末抽出一天時間經過官網還有各類博客文章算是瞭解了一些內容,起碼能夠在項目中本身完成 .babelrc
的配置了。css
這篇文章就是把本身的理解和找到的優秀文章的內容作一融合和整理,理解有誤的地方還請你們批評指正~html
由於主要是面對項目,因此本文內容主要仍是圍繞 .babelrc
展開,與babel
相關的其餘工具無關。vue
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
在項目中咱們使用 Babel 作轉碼通常使用配置文件的形式。Babel 的配置文件名爲 .babelrc
而且一般放在項目根路徑下,其格式大體以下:webpack
{ "env": { "production": { "presets": [], // 轉碼規則 "plugins": [], // 插件 "ignore": ["node_modules/"] // 轉碼時候忽略的文件 } } }
這裏的 env
的值取得是項目中的 process.env.BABEL_ENV
若是該值找不到,則取 process.env.NODE_ENV
最後若是該值還找不到,則設爲 development
git
plugins
優先於 presets
plugins
從數組第一個到最後一個進行編譯presets
從數組最後一個到第一個進行編譯 ,這個目的主要爲了向後降級presets
用於設置轉碼的規則,經常使用的 presets
有 env
和 stage-x
github
關於 env
後文會提到,先來看看 stage-x
web
stage-x
是新特性歸入標準所通過的幾個階段,x
值越小,表示階段越靠後,靠後的階段包含前面的全部內容,即stage-0
包含stage-1/2/3
的全部內容
上圖是 stage-2
的 index.js
文件,能夠看到其中直接引用了 stage-3
的全部特性。vue-cli
實際上來講,presets
就是 plugins
的集合,若是沒有 preset
也是能夠完成代碼轉換工做的,以下。npm
{ "plugins": [ "check-es2015-constants", "es2015-arrow-functions" ] }
可是因爲這麼配置過於繁瑣,所以 Babel 把一些屬於同一標準的 transform-plugins
劃歸到一個 presets
中,這樣有了 presets
就不用再一個一個地導入 transform-plugins
了。
Babel 默認只轉換 JS 語法,而不轉換新的 API ,新標準中的全局對象和定義在這些全局對象上的方法都不會轉碼,這些 API 不少,具體參考 definitions.js
這就致使了 babel-polyfill
和 babel-runtime
的產生
polyfill
一次性所有引入,無論你在項目中是否真正用到polyfill
因此該包應該被添加到 dependency
webpack
結合使用時候須要放在 entry
數組中 entry: ["babel-polyfill", "app.js"]
與 babel-polyfill
的一次性引入不一樣,babel-runtime
支持本身手動引入 helper
函數,來完成對某一 API 的轉碼。它更像是一個個分散的 polyfill
模塊。
顯而易見 babel-runtime
的缺點之一就是每次使用 API 的時候,都須要咱們進行手動引入,很麻煩;此外,在代碼中直接引入 helper
函數,會致使打包的文件中出現不少重複 helper
代碼。所以如今實際工做中會使用 babel-runtime + babel-plugin-transform-runtime
的形式
這個包能夠幫咱們完成 babel-runtime
中 helper
函數的自動引入,而且它還作了公用方法的抽離,你引入的函數都是引用自一個地方,就避免了重複的代碼
該包依賴 babel-runtime
,這也是爲何咱們在使用 webpack
配置 babel 的時候,只須要安裝 babel-plugin-transform-runtime
的緣由,
即 devDependencies
裏只看見了 babel-plugin-transform-runtime
該插件主要作了三件事:
generators/async
方法、函數時自動調用 babel-runtime/regenerator
Map
或者內置的東西時自動調用 babel-runtime/core-js
babel helpers
並替換使用 babel-runtime/helpers
來替換'foobar'.includes('foo')
不能轉化通常直接默認就行,不須要對該插件進行配置
{ "plugins": [ ["transform-runtime", { "polyfill": true, // 是否把新特性轉換爲非全局的 polyfill "helpers": true, // 是否用模塊中的 helpers 替換內聯 helpers "regenerator": true, // 是否把生成器函數轉換爲非全局的 polyfill "moduleName": "babel-runtime" // 導入 helpers 的時候的模塊路徑 }] ] }
.babelrc
轉碼前的 a.js
轉碼後的 a-compiled.js
能夠看到實例方法 "foo".includes('f')
並無被轉換
.babelrc
轉碼前的 b.js
使用 babel 轉碼後,Set
轉碼成功,而且能夠看到在轉碼後的文件中,打印的並非原生的 Set
,而是 babel 爲咱們包裝的一個替代原生 Set
的模塊,避免了全局污染。
當咱們把 .babelrc
中改成 polyfill: false
時,再次對 b.js
轉碼,轉碼後,語句沒有被處理。打印的就是原生的 Set
,污染了全局變量。
若是須要對實例方法進行轉碼,能夠這麼來,固然你須要在 .babelrc
裏改成 polyfill: true
,否則沒有這個 polyfill
根本沒有這些方法。
轉碼前:
轉碼後:
若是非要在不支持的環境下使用實例方法的話,就還得藉助 babel-polyfill
了(或者你本身實現一個)。不過好像目前瀏覽器端對這種諸如 includes
、repeat
之類的方法支持的還不錯了。
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 可能會有問題
通常不推薦使用鬆散模式
簡單來講,鬆散模式轉換後的代碼很容易就能看懂,並且很像咱們平時寫的代碼,但這種不嚴謹的轉換可能會形成問題,因此在開發中是不推薦的。
感覺一下:
轉碼前:
轉碼後(正常):
轉碼後(鬆散):
modules
把 ES6 模塊語法轉爲另外一個模塊類型,默認 commonjs
如今的webpack 4.x
已經把模塊統一的任務完成了,因此這裏就不須要babel
來作了,因此在vue-cli
這種用webpack
打包的腳手架裏,你會看到.babelrc
文件中有module: false
這就是爲了防止與webpack
衝突
include
指定一組老是包括的插件,當原生實現有問題,或存在不支持或支持很差的特性時候使用,默認爲 []
include
和exclude
只工做於包含在preset
裏有的插件中,若是要使用preset
裏不包含的插件,直接填在.babelrc
的plugins
中
exclude
指定一組老是不包括的插件,默認爲 []
useBuiltIns
默認爲 false
會啓用一個插件來根據使用狀況去按需加載 polyfill
來替代 import "babel-polyfill"
語句
全部的工具建議都在項目中安裝,而不是採用全局安裝
babel-cli
用於命令行轉碼babel-node
跟隨 babel-cli
安裝,可直接運行 ES6 代碼,由於採用這種方式是實時轉碼的,轉碼的全部工具都存在內存中,產生大量資源消耗所以只適合在開發中使用babel-register
改寫 require
命令,每次使用 require
加載 js
文件時候,就會先轉碼,由於是實時轉碼,只適合在開發環境使用babel-core
提供 Babel 的 API,以後能夠採用編程方式使用 Babel