Babel 插件

Babel 是一个编译器,和其他编译器一样,编译过程分为三个阶段,分别是解析(parsing)、转换(transforming)和生成(generate)。其中分析和生成阶段由 Babel 核心完成,而转换阶段,则由Babel插件完成。所以如果我们要实现代码的转换,需要为 Babel 添加插件。Babel 也提供了很多的接口来供我们编写自身的插件来转换我们的实际代码。

插件的介绍

下面是一个典型的 Babel 插件结构:

export default function({ types: babelTypes }) {
  return {
    visitor: {
      Identifier(path, state) {},
      ASTNodeTypeHere(path, state) {}
    }
  };
};

其中我们需要关注的内容如下:

  • babelType:类似 lodash 那样的工具集,主要用来操作 AST 节点,比如创建、校验、转变等。例如判断某个节点是不是标识符。
  • path:AST 中有很多节点,每个节点可能有不同的属性,并且节点之间可能存在关联。path 是个对象,它代表了两个节点之间的关联。我们可以在 path 上访问到节点的属性,也可以通过 path 来访问到关联的节点。
  • state:代表了插件的状态,我们可以通过 state 来访问插件的配置项。
  • visitor:Babel 采取递归的方式访问 AST 的每个节点,之所以叫做 visitor,只是因为有个类似的设计模式叫做访问者模式,不用在意背后的细节。
  • Identifier、ASTNodeTypeHere:AST 的每个节点,都有对应的节点类型,比如标识符、函数声明等,可以在 visitor 上声明同名的属性,当 Babel 遍历到相应类型的节点,属性对应的方法就会被调用,传入的参数就是 path、state。

插件的使用

例如我们来实现一个简单的插件,将所有名称为 hello 的标识符,转成 xkd。

首先要确保已经安装了 @babel/cli 依赖,如果没有可以执行下述命令:

npm install --save-dev @babel/cli

然后可以开始创建插件,判断标识符的名称是否是 a,如果是则替换成 xkd,plugin.js 文件内容如下所示:

module.exports = function({ types: babelTypes }) {
    return {
      name: "simple-plugin-replace",
      visitor: {
        Identifier(path, state) {
          if (path.node.name === 'a') {
            path.node.name = 'xkd';
          }
        }
      }
    };
};

然后在 index.js 文件中编写源代码,例如:

var a = 10;
function func(){
    var a = 20;
    console.log(a);
}

执行如下命令:

npx babel --plugins ./plugin.js index.js

输出的转码结果为:

"use strict";

var xkd = 10;
function func() {
    var xkd = 20;
    console.log(xkd);
}

可以看到,代码中的所有标识符 a 都被替换成了 xkd。

插件配置

插件可以有自己的配置项。我们可以修改前面的例子,看下在 Babel 插件中如何获取配置项。

示例:

例如我们修改 .babelrc 文件中的配置项:

{
    "plugins": [ ["./plugin", {
      "a": "one",
      "b": "two"
    }] ]
}

然后修改插件代码,从 state.opts 中获取到配置参数。

module.exports = function({ types: babelTypes }) {
  return {
    name: "simple-plugin-replace",
    visitor: {
      Identifier(path, state) {
        let name = path.node.name;
        if (state.opts[name]) {
          path.node.name = state.opts[name];
        }
      }
    }
  };
};

在 index.js 文件中写入需要用到的测试代码:

let a = 10;
let b = 20;

运行转码命令 npx babel index.js,输出转码后的结果如下:

let one = 10;
let two = 20;

转译插件

插件可以分为两种,分是转译插件和语法插件,转译插件可以用于转译代码。同一类语法可能同时存在语法插件版本和转译插件版本,如果我们使用了转译插件,就不用再使用语法插件了,因为转换插件将启用相应的语法插件。

ES3

  • member-expression-literals
  • property-literals
  • reserved-words

ES5

  • property-mutators

ES2015

  • arrow-functions
  • block-scoped-functions
  • block-scoping
  • classes
  • computed-properties
  • destructuring
  • duplicate-keys
  • for-of
  • function-name
  • instanceof
  • literals
  • new-target
  • `object-super``
  • parameters
  • shorthand-properties
  • spread
  • sticky-regex
  • template-literals
  • typeof-symbol
  • unicode-escapes
  • unicode-regex

ES2016

  • exponentiation-operator

ES2017

  • async-to-generator

ES2018

  • async-generator-functions
  • dotall-regex
  • named-capturing-groups-regex
  • object-rest-spread
  • optional-catch-binding
  • unicode-property-regex

Modules

  • modules-amd
  • modules-commonjs
  • modules-systemjs
  • modules-umd

Experimental

  • class-properties
  • decorators
  • do-expressions
  • export-default-from
  • export-namespace-from
  • function-bind
  • function-sent
  • logical-assignment-operators
  • nullish-coalescing-operator
  • numeric-separator
  • optional-chaining
  • partial-application
  • pipeline-operator
  • private-methods
  • throw-expressions
  • private-property-in-object

语法插件

当我们添加语法插件之后,在解析这一步就使得 Babel 能够解析特定类型的语法。

或者也可以从 Babel 解析器提供任何插件选项,例如 .babelrc 文件中可以像下面这样配置:

{
  "parserOpts": {
    "plugins": ["jsx", "flow"]
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容