Babel知識體系淺談

人間失格發表於2019-02-27

我個人正在寫Node.js的系列學習筆記node-learning-manual,包含了Node.js的基本模組和工程化相關的知識, 如果對你有幫助,請點個start,您的支援是對我最大的鼓勵。

前言

前端發展到現在,可謂是混亂至極,已經遠遠超出我對前端所謂一把jQuery抄起來就是懟,

Webpack, babel, node.js, react, vue各種工程框架,構建工具你不會點好像都不算是個合格的

前端工程師,語法相關的ES6/7總是繞不過Babel,這篇文章就是直接討論Babel。

本文只要圍繞以下幾塊來說:

  1. Babel編譯過程介紹
  2. Babel外掛及預設
  3. Babel-register在專案中的使用
  4. babel的polyfill引入機制
  5. babel在前端工程的定位

Babel編譯過程介紹

  1. 核心包

    // 暴露babel.transform方法來編譯source code
    babel-core
    // 語法字串解析parser
    babylon
    // 結合plugins遍歷AST語法樹
    babel-traverse
    // 生成最後的編譯字串
    babel-generator
    複製程式碼
  2. babel編譯流程

    input string
    -> babylon parser
    -> AST
    -> babel-traverse  //使用plugins遍歷AST語法樹
    -> AST
    -> babel-generator
    -> output string
    複製程式碼

Babel是一個JavaScrpit的編譯器,從巨集觀的角度來看,它有三個執行階段:解析,轉化,生成。基本上如果不設定配置檔案.babelrc,Babel執行的結果便是 const babel = code => code ,通過讀取程式碼,最後生成一樣的程式碼。Babel的最核心的概念便是外掛,通過在配置檔案 .babelrc中新增不同的外掛基本可以做所有的事情。

Babel外掛(plugins)及預設(presets)

首先聊聊外掛與預設的關係,官方預設便是由官方評審維護的一系列外掛組合。外掛與預設的關係便是父子集合的關係。

每年babel都會評估當年的外掛,babel-preset-env 取代了 es2015, es2016, es2017 以及最新的程式碼

Babel-register在專案中的使用

babel-register的設計思想非常厲害,簡單的來說就是require hook。也是babel常見的一種使用方法。

這種方法只需要引入檔案就可以執行 Babel,或許能更好地融入你的專案設定。

讓我們先在專案中建立index.js檔案

// index.js
console.log("hello world");
複製程式碼

接著需要我們安裝babel-register

$ npm install i -D babel-register
複製程式碼

接著,在專案中建立 register.js 檔案並新增如下程式碼:

require("babel-register");
require("./index.js");
複製程式碼

然後我們只需要啟動 node register.js 便可,通過修改require function,對所有的通過require引入的程式碼先經過babel編譯一遍,再給到runtime執行。

babel的polyfill引入機制

Babel 幾乎可以編譯所有時新的 JavaScript 語法,但對於 APIs 來說卻並非如此。

比方說,下列含有箭頭函式的需要編譯的程式碼:

function addAll() {
  return Array.from(arguments).reduce((a, b) => a + b);
}
複製程式碼

最終會變成這樣

function addAll() {
  return Array.from(arguments).reduce(function(a, b) {
    return a + b;
  });
}
複製程式碼

然而,它依然無法隨處可用因為不是所有的 JavaScript 環境都支援 Array.from

為了解決這個問題,我們使用一種叫做 Polyfill(程式碼填充,也可譯作相容性補丁) 的技術。 簡單地說,polyfill 即是在當前執行環境中用來複制(意指模擬性的複製,而不是拷貝)尚不存在的原生 api 的程式碼。 能讓你提前使用還不可用的 APIs,Array.from 就是一個例子。

要使用 Babel polyfill,首先用 npm 安裝它:

$ npm install --save babel-polyfill
複製程式碼

然後只需要在檔案頂部匯入 polyfill 就可以了:

import "babel-polyfill";
複製程式碼

所以我的個人建議是按需引入core-js的模組而不是整個babel-polyfill bundle,來對ES6/7新增的資料物件和方法做polyfill。

babel-runtime引入機制

為了實現 ECMAScript 規範的細節,Babel 會使用“助手”方法來保持生成程式碼的整潔。

由於這些助手方法可能會特別長並且會被新增到每一個檔案的頂部,因此你可以把它們統一移動到一個單一的“執行時(runtime)”中去。

通過安裝 babel-plugin-transform-runtimebabel-runtime 來開始。

$ npm install --save-dev babel-plugin-transform-runtime
$ npm install --save babel-runtime
複製程式碼

然後更新 .babelrc

  {
    "plugins": [
+     "transform-runtime",
      "transform-es2015-classes"
    ]
  }
複製程式碼

現在,Babel 會把這樣的程式碼:

class Foo {
  method() {}
}
複製程式碼

編譯成:

import _classCallCheck from "babel-runtime/helpers/classCallCheck";
import _createClass from "babel-runtime/helpers/createClass";

let Foo = function () {
  function Foo() {
    _classCallCheck(this, Foo);
  }

  _createClass(Foo, [{
    key: "method",
    value: function method() {}
  }]);

  return Foo;
}();
複製程式碼

這樣就不需要把 _classCallCheck_createClass 這兩個助手方法放進每一個需要的檔案裡去了。

babel總結

babel的出現讓開發者可以自由的採用ES6/7的語法來編寫JS專案,極大的豐富了開發 (browser, node) 層面的JS語言特性。

babel的AST parser、polyfill、 register一起完成了babel體系對JS的完備解決方案。

參考資料

babel 知識體系漫遊

babel handbook

babel docs

我個人正在寫Node.js的系列學習筆記node-learning-manual,包含了Node.js的基本模組和工程化相關的知識, 如果對你有幫助,請點個start,您的支援是對我最大的鼓勵。

相關文章