1. 程式人生 > >babel的初步瞭解

babel的初步瞭解

前段時間開始研究ast,然後慢慢的順便把babel都研究了,至於ast稍後的時間會寫一篇介紹性部落格專門介紹ast,本部落格先介紹一下babel的基本知識點。

  • 背景:

由於現在前端出現了很多非es5的語法,如jsx,.vue,ts等等的格式和寫法,如果要在瀏覽器的裝置上識別並執行,需要額外將這些非傳統格式的語法轉成傳統的es5格式,而babel外掛,就是用來將非es5格式的語法轉成es5語法。

babel其實是一個直譯器,它主要講進行中的程式碼分為三個階段執行:解釋,轉換,生成。其中babel外掛或者其他外掛都是在轉換階段起作用。

  • babel核心包:

babel既然是個直譯器,那麼就會擁有解釋,遍歷,以及生成的一系列工具和api:

1)babylon:babel裡面用來將js程式碼詞法分析,生成ast,他的結構有些像acron,它的返回的結構裡面包含著ast和tokens。


require("babylon").parse("code", {
  // parse in strict mode and allow module declarations
  sourceType: "module",

  plugins: [
    // enable jsx and flow syntax
    "jsx",
    "flow"
  ]
});

sourceType: module表示的是在嚴格模式下解析並且允許模組定義(即能識別import和expor語法);script識別不了。

2)babel-traverse:功能就像estraverse一樣,主要是給plugin提供遍歷ast節點的功能;


var babylon = require('babylon');
var result = babylon.parse(code, { sourceType: "module",});
console.log('result:', result);

import traverse from "babel-traverse";

traverse(result, {
    enter(node) {
       console.log(node);
    }
});

3)babel-generator:將ast生成js程式碼;


var babylon = require('babylon');
var result = babylon.parse(code, { sourceType: "module",});
console.log('result:', result);

import traverse from "babel-traverse";
import generate from 'babel-generator';

traverse(result, {
    enter(node) {
       console.log(node);
    }
});

var conde1 = generate(result);
console.log('generate:', conde1);
  • babel工具包:

要完成複雜的轉換工作,單靠核心包是不能完成的,所以必要還要依賴於其他工具包輔助。

1)babel-types:包含著ast中的所有型別,可以生成一個ast的節點,然後替換真是ast的節點,從而改變ast的內容(ast工具庫,類似於lodash,具有校驗,建立和轉換ast的方法)。


import * as t from "babel-types";

console.log(t.stringLiteral("my-module"));

語法:t.anyTypeAnnotation(內容) // 最終返回一個型別的物件

2)babel-template:可以通過字串的形式生成一個ast;


import template from "babel-template";
const buildRequire = template(`
  var IMPORT_NAME = require(SOURCE);
`);

const ast2 = buildRequire({
    IMPORT_NAME: t.identifier("myModule"),
    SOURCE: t.stringLiteral("my-module")
});

console.log('ast2', ast2);

3)babel-helps: 主要是用來協助babel轉換;

4)babel-core-frame: 主要是用來將錯誤資訊打印出來;

5)babel-cli:babel的命令列工具,通過命令列對js程式碼進行轉譯;

6)babel-register: 因為babel工具檔案,外掛裡面使用了很多require,而 該檔案可以將node中的require於babel中的require繫結,從而可以使用require引入檔案;

7)babel-plugin-xxx: 在轉換過程中使用的外掛;

8)babel-plugin-transform-xxx: 在transerform過程中使用到的外掛;

(.babelrc檔案:該檔案會在babel編譯過程中,自動配置babel的引數,babel的執行環境--env,babel的設定---preset,babel的所需要用到的外掛---plugins等)

9)babel-core:該核心包包含著babel的核心(babel-lon,babel-traverse,babel-generate),提供了更多更友善的api給開發者使用。

  • babel編譯原理:

編譯器就是講高階的語言或者語法,編譯成更進階機器識別的語言和語法;

babel其實更像一個轉譯器,因為它主要是將高階的js語法轉成低階的語法;

他們兩者雖然有區別,但有很多相似之處(都是經歷三個過程:解析,處理,生成);

以es6轉成es5為例:

ES6程式碼輸入 ==》 babylon進行解析 ==》 得到AST ==》 plugin用babel-traverse對AST樹進行遍歷轉譯 ==》 得到新的AST樹 ==》 用babel-generator通過AST樹生成ES5程式碼

  • babel-pollfill,babel-runtime,transfer-runtime的區別:

babel-pollfill是針對於應用和頁面範圍內,對新的物件和新的語法進行相容,主要是通過一些輔助函式進行相容新的語法,但如果針對外部的庫使用,就會產生汙染全域性環境的影響,一般對專案程式碼使用;

babel-runtime是對於外部外掛和庫的語法相容,能將新的物件和語法,通過在執行時,把對應的可識別的語法和物件匹配出來並進行轉換,從而顯示在執行時進行語法降級相容,且不會產生全域性汙染,一般對外部的外掛使用;

transfer-babel是對babel-runtime進行封裝,新的語法,物件能通過該外掛,換種形式引用runtime的東西;

(其實runtime,pollfill都是建立在core-js之上的)。

對於babel的外掛,主要是因為生成的ast的底層中有一個accept方法,專門用來接收visitor(外掛)訪問者物件,然後在visitor中定義各種節點型別的操作-visite,每個visite都可以接受一個path引數(節點資訊,節點和位置資訊的物件,其包含很多有用的方法),在visit中處理path,從而實現轉換的作用。


const result = babel.transform(code, {
    plugins: [{
        visitor
    }]
})
console.log(result.code);

至於visitor後續會詳細介紹。

整個babel的結構圖,我大概花了一張圖表示出來:

而babel和webpack的協同開發,我也大概花了一張圖表示他們之間的關係,但裡面的原理,我後續會再去研究,研究好再分享一下:

以上是我對babel的初步理解,如果有不正確的地方,歡迎指出。

來源:https://segmentfault.com/a/1190000017499449