Babel

babel 是現代前端工程師都不陌生的工具,它可以將 ES6 (+) 的語法轉換為 ES5 甚至是更低的版本,利用 babel 可以讓開發者即刻享受到 ES6 語法所帶來的便利性。 然而許多 babel 相關的名詞卻常常困擾想要入門的新手們,因此利用本文簡介那些與 babel 相關的名詞,以 babel 6 為主。

本篇將會會介紹到:

  • .babelrc
  • babel-cli (with babel-node)
  • babel-preset vs. babel-plugin
  • babel-register
  • babel-polyfill
  • babel-plugin-transform-runtime & babel-runtime
  • babel-loader
  • babel-eslint

本文用意並非完善的介紹整個 babel 生態系,而是作者整理自己常見且容易搞錯的 babel 相關名詞。

一、.babelrc

這是 babel 這個工具需要用到的設定檔,以下所介紹到的各項都需要該設定檔讓 babel 有轉換的依據。

方法一:

直接寫獨立的 .babelrc 檔,一個基本的格式如下:

{
  "presets": ["es2015"]
}

方法二:

直接寫進 package.json

{
  "name": "my-package",
  "version": "1.0.0",
  "babel": {
    // your babel config here
  }
}

註:方法二雖然可以這樣寫,但不建議使用,因為在 react-native 會出現已知的問題

二、babel-cli

利用 npm 安裝 babel-cli 將會同時註冊 babelbabel-node 兩個最常使用的指令。

$ npm install babel-cli --save-dev

利用上述指令安裝在 project 的目錄底下。

babel

可以直接在終端機利用 babel 指令做 ES6 的語法轉換, 常用的情景為將 src 資料夾 build 成 lib 資料夾, 身為 library 開發者,以不要預設使用者有 ES6 的環境為佳, 上述簡單的指令如下:

$ babel src -d lib

若需更多參數,請參考官方教學。

babel-node

可以利用 babel-node myEs6.js 直接運行 ES6 的 code, 當然需要 .babelrc 檔還有相關的 presets 或是 plugins 做為 babel 轉換的依據。

babel-node 執行的時候會預設載入 babel-polyfill 使用, 因此會佔大量的記憶體空間,官方不建議在 production 環境使用。

三、babel-preset vs. babel-plugin

presets 和 plugins 這兩個 key 在 .babelrc 檔內會很常看到, 其中的差異便是一個 preset 可以包含其他不同 presets 或是不同的 plugins。

例如 babel-preset-es2015 當中包含了 transform-es2015-arrow-functions transform-es2015-block-scoped-functions 等 21 個不同的 plugins。

順序問題

babel 在執行 transform 的過程,會 plugins 先載入,且按照由上往下(由左向右)的順序載入, 但是要注意的事情,presets 會在 plugins 之後,然後載入的順序是由下往上(由右向左)的反向順序。

stage

babel 針對 stage 有實作幾個不同的 presets,包含了

  • preset-stage-0
  • preset-stage-1
  • preset-stage-2
  • preset-stage-3

stage 數字越大的 preset 所包含的 plugins 代表即將進入 ECMA262 standard, TC39 Process, 官方預設的範例 stage 0 的 preset 使用就是因為其包含了 stage 1, 2, 3 的 presets, 而許多開發者直接用 stage 0,會把全部 stage 都載入,建議花時間了解各個 preset-stage 分別載入哪些 plugins 為佳。

stage 是會隨著時間演進,在不同的階段所看到的 stage 內容可能都不一樣。

四、babel-register

當載入 babel-register 後,其接下來的 es6 語法都可以被設定的 .babelrc 做轉換,

載入的方式有兩種:

方法一:

額外建立一個進入點檔案,由於在這個進入點 node 並不知道 es6 語法, 因此於此需要利用 require('babel-register') 的方式載入

進入點檔名以 entry.js 為例:

require('babel-register');
require('./yourEs6Index');

因此未來執行 node entry.js 就可以利用 babel-register 動態載入的方式進行轉換語法。

方法二:

在終端機執行 node 的時候,直接利用 -r 參數帶入 babel-register-r 等於 --require 代表 module to preload

$ node -r babel-register yourEs6Index.js

五、babel-polyfill

什麼是 polyfill?

wiki: In web development, a polyfill is code that implements a feature on web browsers that do not support the feature.

因此 babel-polyfill 顧名思義就是 babel 幫我們做了一些現階段還沒有被各家瀏覽器通用支援的 feature,好讓我們在現階段就可以利用一些未來原生的語法,例如:Promise, Array.from, Object.assign, Array.includes 等。 像是 Chrome 對於 es6 的支援度一直以來都蠻高的,但是並非每家瀏覽器廠商都能支援,因此需要有 polyfill。

babel-node 當利用 babel-node 去運行 js 檔的時候,會預設載入 babel-polyfill, 因此你即可利用 babel-node run 一個帶有 promise 的 js 檔, 而不需再另外 require bluebird 等套件。

babel-polyfill 主要 includes 了 regenerator runtimecore-jsregenerator runtime 就是將 generator/async 轉換成 es5 語法,而 core-js 是 Modular standard library for JavaScript 集合,詳細請參閱連結。

六、babel-plugin-transform-runtime & babel-runtime

在做轉換的時候,若利用 babel-polyfill 會做 global scope,所以當你今天是要做 lib/tool 模式,沒辦法控制你的運行環境,則不適合利用 babel-polyfill,需要用 babel-plugin-transform-runtime 為佳。

  1. babel-plugin-transform-runtime 會把多個檔案 reference 到 babel-runtime 這個 package,因此當你使用 transform-runtime 就一定要裝 babel-runtime
  2. babel-plugin-transform-runtime 的轉換機制也是 alias 到 core-js,就和 babel-polyfill 一樣,所以不用再 require babel-polyfill
  3. 官方建議安裝方法如下: transform 安裝進 devDependencies
$ npm install --save-dev babel-plugin-transform-runtime
$ npm install --save babel-runtime

七、babel-loader

loaderwebpack 用來載入各種不同類型檔案的套件,而 babel-loader 讓 webpack 可以用來執行 babel 轉換的的一種套件。

利用 babel-loader 可以利用 webpack 打包時候同時進行 babel 的轉換,以下是簡單範例檔:

module: {
  loaders: [
    {
      test: /\.js$/,
      loaders: ['babel'],
      exclude: /node_modules/,
    },
  ],
},

因為 babel-loader 的速度很慢,官方建議把 node_modules exclude 掉。

八、babel-eslint

ESLint 堪稱是近代偉大的 linter 發明之一,它可以讓使用者高度客製化的 parser 語法,而目前原生的 ESLint 支援的語法有 ES6/ES7, JSX, and object rest/spread,如果你用到的更多 babel 語法則需要 babel-eslint 來幫忙。

$ npm install eslint@3.x babel-eslint@6 --save-dev

.eslintrc 範例檔

{
  "parser": "babel-eslint",
  "rules": {
    "strict": 0
  }
}

結論

當然 babel 的套件不僅僅如此,還有 babelify, babili 等許多相關工具尚未有時間介紹,本篇所提及的介紹希望能對於部分開發者有幫助。 若有不清楚或者會誤導讀者的方向,還請不吝指教。