iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 7
1
Modern Web

前端建置工具完全手冊系列 第 7

Day 7: babel 的套件

babel 實際上拆成好幾個套件,有些平常基本上也用不到,因為那一般而言是開發 plugin 時才會去接觸到的,這邊就來一一介紹跟 plugin 還有一般使用有關的:

  • @babel/core: 這其實之前就提過了,這是 babel 最主要的一個套件,它提供了 API 把其它的套件串起來使用,如果你要在程式中呼叫 babel 使用也是用這個套件
  • @babel/traverse: 這包含了走訪 AST 的部份,也是 plugin 最主要會用到的功能
  • @babel/types: 這個套件在官方的說明中寫著它相當於針對 AST 的 lodash ,它提供了三種功能,建構 AST 的節點,判斷是不是某種 AST 的節點,與 assert 是不是某種節點
  • @babel/template: 當你要建構比較複雜的 AST 用的,如果用 @babel/types 一個一個節點建立的話可能會很累
  • @babel/parser: 就是 babel 的 parser ,負責把 code 轉換成 AST
  • @babel/generator: 負責把 AST 轉回 code

如果你在寫 js 但還沒用過 lodash 或是類似的套件的,推薦你去看看,很好用的,它提供了很多方便的函式

實際使用這些套件大概會像這樣

import { parse } from '@babel/parser'
import traverse from '@babel/traverse'
import generate from '@babel/generator'

const ast = parse(`function square(n) {
  return n * n
}`)

traverse(ast, {
  Identifier(path) {
    if (path.node.name === 'n') {
      path.node.name = 'x' // 可以直接修改 node 的內容
    }
  },
})

console.log(generate(ast).code)

// 輸出應該會是
// function square(x) {
//   return x * x;
// }

上面的提到 @babel/core 把其它的套件都串起來了,那就實際來用用看吧:

import { transformAsync } from '@babel/core'

transformAsync(
  `function square(n) {
    return n * n
  }`,
  // 第二個參數就是傳入像平常寫在 `babel.config.js` 中的設定的內容
  {
    plugins: [
      {
        visitor: {
          Identifier(path) {
            if (path.node.name === 'n') {
              path.node.name = 'x'
            }
          },
        },
      },
    ],
  }
).then((res) => {
  console.log(res.code)
})

但如果你有真的去跑的話,你很可能會發現跑出來的結果跟分開呼叫時不一樣,因為使用 @babel/core 的 API 時預設會設定 sourceTypemodule ,導致最後會加上 "use strict" ,另外雖然這邊的 @babel/core 的 API 是 transformAsync ,但實際上 babel 的轉換過程本身是同步的

雖然 babel 的 core 都有重新 export 底下套件的內容,如果是在寫 plugin 的話,為了避免使用到跟使用者不同版本的套件,應該是要用呼叫 plugin 時傳進來的那個 babel ,而不是使用自己的,所以像上面的那個用法實際上只有在自己用 API 的方式使用 babel 才會出現

上一篇的時候抱歉我記錯了,下一篇終於要來寫第一個 babel plugin 了


上一篇
Day 6: babel 是如何運作的
下一篇
Day 8: 第一個 babel plugin
系列文
前端建置工具完全手冊30

尚未有邦友留言

立即登入留言