babel 7 發佈兩天了,試着對當前項目更新了下,僅此記錄分享css
主要改動參考 官方博客node
官方升級指南react
let a = {b: 11} a?.b // a ? a.b : undefined a &&= b // a = a && (a=b) 或 a = a && b 複製代碼
let c = a ?? b // 只有 a 是 undefined 或 null 時,c 等於 b let res = foo(boo(aaa('nice'))) === let res = 'nice' |> aaa |> boo |> foo 複製代碼
npx babel-upgrade --write
# 或是安裝 babel-upgrade 在 global 並執行 npm install babel-upgrade -g babel-upgrade --write 複製代碼
能夠看到 package.json 中移除了舊版本的依賴,自動新增了新版名稱,.babelrc 文件的配置也會自動修改 可是不會刪除已有的插件,如原來的 transform-decorators-legacywebpack
// 移除就版本依賴後從新安裝依賴git
rm -rf node_modules
yarn install
複製代碼
由於 babel 7 新增的 @babel 命名空間,因此原來的 babel-polyfill 須要修更名稱github
// index.js 頭部導入修改
import '@babel/polyfill' // webpack config 入口修改 entry: ['@babel/polyfill', './src/index.js'], 複製代碼
yarn add @babel/plugin-proposal-decorators -D
複製代碼
注意web
@babel/plugin-proposal-decorators
必須在 @babel/plugin-proposal-class-properties
以前配置"dev": { "plugins": [ "@babel/plugin-proposal-object-rest-spread", "@babel/transform-async-to-generator", [ "@babel/plugin-proposal-decorators", { "legacy": true } ], ["@babel/plugin-proposal-class-properties", { "loose": true }], "@babel/plugin-proposal-optional-chaining", "react-hot-loader/babel", [ "react-css-modules", { "webpackHotModuleReloading": true, "generateScopedName": "[path][name]__[local]--[hash:base64:5]", "filetypes": { ".less": { "syntax": "postcss-less" } } } ], [ "import", { "libraryName": "antd" } ] ] }, 複製代碼
"@babel/plugin-syntax-dynamic-import", "@babel/plugin-syntax-import-meta", "@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-json-strings", [ "@babel/plugin-proposal-decorators", { "legacy": true } ], "@babel/plugin-proposal-function-sent", "@babel/plugin-proposal-export-namespace-from", "@babel/plugin-proposal-numeric-separator", "@babel/plugin-proposal-throw-expressions", "@babel/plugin-proposal-export-default-from", "@babel/plugin-proposal-logical-assignment-operators", "@babel/plugin-proposal-optional-chaining", [ "@babel/plugin-proposal-pipeline-operator", { "proposal": "minimal" } ], "@babel/plugin-proposal-nullish-coalescing-operator", "@babel/plugin-proposal-do-expressions", "@babel/plugin-proposal-function-bind"
好比 es2015 是一套規範,包含大概十幾二十個轉譯插件。若是每次要開發者一個個添加並安裝,配置文件很長不說,npm install
的時間也會很長,更不談咱們可能還要同時使用其餘規範呢。typescript
爲了解決這個問題,babel 還提供了一組插件的集合。由於經常使用,因此沒必要重複定義 & 安裝。(單點和套餐的差異,套餐省下了巨多的時間和配置的精力)express
preset 分爲如下幾種:npm
例如 syntax-dynamic-import
就是 stage-2 的內容,transform-object-rest-spread
就是 stage-3 的內容。
此外,低一級的 stage 會包含全部高級 stage 的內容,例如 stage-1 會包含 stage-2, stage-3 的全部內容。
stage-4 在下一年更新會直接放到 env 中,因此沒有單獨的 stage-4 可供使用。
arrow-functions
,es2017 包含 syntax-trailing-function-commas
。但由於 env 的出現,使得 es2016 和 es2017 都已經廢棄。因此咱們常常能夠看到 es2015 被單獨列出來,但極少看到其餘兩個。很簡單的幾條原則:
preset 的逆向順序主要是爲了保證向後兼容,由於大多數用戶的編寫順序是 ['es2015', 'stage-0']
。這樣必須先執行 stage-0
才能確保 babel 不報錯。所以咱們編排 preset 的時候,也要注意順序,其實只要按照規範的時間順序列出便可。
簡略狀況下,插件和 preset 只要列出字符串格式的名字便可。但若是某個 preset 或者插件須要一些配置項(或者說參數),就須要把本身先變成數組。第一個元素依然是字符串,表示本身的名字;第二個元素是一個對象,即配置對象。
最須要配置的當屬 env,以下:
"presets": [ // 帶了配置項,本身變成數組 [ // 第一個元素依然是名字 "env", // 第二個元素是對象,列出配置項 { "module": false } ], // 不帶配置項,直接列出名字 "stage-2" ]
由於 env 最爲經常使用也最重要,因此咱們有必要重點關注。
env 的核心目的是經過配置得知目標環境的特色,而後只作必要的轉換。例如目標瀏覽器支持 es2015,那麼 es2015 這個 preset 實際上是不須要的,因而代碼就能夠小一點(通常轉化後的代碼老是更長),構建時間也能夠縮短一些。
若是不寫任何配置項,env 等價於 latest,也等價於 es2015 + es2016 + es2017 三個相加(不包含 stage-x 中的插件)。env 包含的插件列表維護在這裏
下面列出幾種比較經常使用的配置方法:
{ "presets": [ ["env", { "targets": { "browsers": ["last 2 versions", "safari >= 7"] } }] ] }
如上配置將考慮全部瀏覽器的最新2個版本(safari大於等於7.0的版本)的特性,將必要的代碼進行轉換。而這些版本已有的功能就不進行轉化了。這裏的語法能夠參考 browserslist
{ "presets": [ ["env", { "targets": { "node": "6.10" } }] ] }
如上配置將目標設置爲 nodejs,而且支持 6.10 及以上的版本。也可使用 node: 'current'
來支持最新穩定版本。例如箭頭函數在 nodejs 6 及以上將不被轉化,但若是是 nodejs 0.12 就會被轉化了。
另一個有用的配置項是 modules
。它的取值能夠是 amd
, umd
, systemjs
, commonjs
和 false
。這可讓 babel 以特定的模塊化格式來輸出代碼。若是選擇 false
就不進行模塊化處理。
這是 babel 7 的一個重大變化,把全部 babel-*
重命名爲 @babel/*
,例如:
babel-cli
變成了 @babel/cli
。babel-preset-env
變成了 @babel/preset-env
。進一步,還能夠省略 preset
而簡寫爲 @babel/env
。babel-plugin-transform-arrow-functions
變成了 @babel/plugin-transform-arrow-functions
。和 preset
同樣,plugin
也能夠省略,因而簡寫爲 @babel/transform-arrow-functions
。這個變化不僅僅應用於 package.json 的依賴中,包括 .babelrc 的配置 (plugins
, presets
) 也要這麼寫,爲了保持一致。例如
{
"presets": [
- "env" + "@babel/preset-env" ] }
順帶提一句,上面提過的 babel 解析語法的內核 babylon
如今重命名爲 @babel/parser
,看起來是被收編了。
上文提過的 stage-x 被刪除了,它包含的插件雖然保留,但也被重命名了。babel 團隊但願更明顯地區分已經位於規範中的插件 (如 es2015 的 babel-plugin-transform-arrow-functions
) 和僅僅位於草案中的插件 (如 stage-0 的 @babel/plugin-proposal-function-bind
)。方式就是在名字中增長 proposal
,全部包含在 stage-x 的轉譯插件都使用了這個前綴,語法插件不在其列。
最後,若是插件名稱中包含了規範名稱 (-es2015-
, -es3-
之類的),一概刪除。例如 babel-plugin-transform-es2015-classes
變成了 @babel/plugin-transform-classes
。(這個插件我本身沒有單獨用過,慚愧)
babel 7.0 開始再也不支持 nodejs 0.10, 0.12, 4, 5 這四個版本,至關於要求 nodejs >= 6 (當前 nodejs LTS 是 8,要求也不算太過度吧)。
這裏的再也不支持,指的是在這些低版本 node 環境中不能使用 babel 轉譯代碼,但 babel 轉譯後的代碼依然能在這些環境上運行,這點不要混淆。
在 babel 6 時,ignore
選項若是包含 *.foo.js
,實際上的含義 (轉化爲 glob) 是 ./**/*.foo.js
,也就是當前目錄 包括子目錄 的全部 foo.js
結尾的文件。這可能和開發者常規的認識有悖。
因而在 babel 7,相同的表達式 *.foo.js
只做用於當前目錄,不做用於子目錄。若是依然想做用於子目錄的,就要按照 glob 的完整規範書寫爲 ./**/*.foo.js
才能夠。only
也是相同。
這個規則變化只做用於通配符,不做用於路徑。因此 node_modules
依然包含全部它的子目錄,而不僅僅只有一層。(不然全世界開發者都要爆炸)
和 babel 6 不一樣,若是要使用 @babel/node
,就必須單獨安裝,並添加到依賴中。
在提到刪除 stage-x 時候提過這個工具,它的目的是幫助用戶自動化地從 babel 6 升級到 7。
這款升級工具的功能包括:(這裏並不列出完整列表,只列出比較重要和經常使用的內容)
babel-*
替換爲 @babel/*
@babel/*
依賴的版本更新爲最新版 (例如 ^7.0.0
)scripts
中有使用 babel-node
,自動添加 @babel/node
爲開發依賴babel
配置項,檢查其中的 plugins
和 presets
,把短名 (env
) 替換爲完整的名字 (@babel/preset-env
)plugins
和 presets
,把短名 (env
) 替換爲完整的名字 (@babel/preset-env
)preset-stage-x
,若有替換爲對應的插件並添加到 plugins
使用方式以下:
# 不安裝到本地而是直接運行命令,npm 的新功能 npx babel-upgrade --write # 或者常規方式 npm i babel-upgrade -g babel-upgrade --write
babel-upgrade
工具自己也還在開發中,還列出了許多 TODO 沒有完成,所以以後的功能可能會更加豐富,例如上面提過的 ignore
的通配符轉化等等。