Babel Pulgin 从零开始

294 阅读3分钟
  • 打算重构一款旧的 babel 插件,所以想着记录一下整个过程,让更多的人能快速学习 babel 插件的搭建。
  • 也会有些工程化理念。

搭建

  1. 新建文件夹
  2. 使用工具初始化项目,指令 yarn init  or npm init
  3. 添加 .gitignore 文件,并在里面写上 node_modules 
  4. 在项目文件夹中,创建文件夹 src , src 主要存储源码。
  5. src 文件夹中,创建 index.js 

简单 babel 跑通流程

编写简单语句

src/index.js 写入

export default function({ types: t }) {
  return {
    visitor: {
      BinaryExpression(path, state) {
        if (path.node.operator !== '===') {
          return;
        }
        path.node.left = t.identifier('left')
        path.node.right = t.identifier('right');
      }
    }
  }
}

这里使用的是 babel 的访问者设计理念编码,没有使用工具集。可以自行学习相关知识github.com/jamiebuilds…

添加执行语句

package.json 文件里添加

"scripts": {
    "build": "babel src -d lib"
  },

这个语句是将 babel 插件源码,转换输出至 lib 目录存储,当我们发布到 npm 时,需要更改 package.json 的 main 属性,将主体指向转换后的代码。

"main": "lib/index.js",

添加 babel 依赖

因为我们编写插件也是 js,所以也会有语法支持问题,所以我们项目也需要配置 babel,保证最终代码的质量和兼容性。

  • 项目根目录添加文件 .babelrc 
  • 添加依赖 yarn add @babel/cli @babel/core @babel/preset-env -D or npm install --save-dev @babel/cli @babel/core @babel/preset-env 
  • .babelrc 文件添加
{
  "presets": ["@babel/preset-env"]
}
  • 运行 build 指令, yarn build or npm run build 

可以看项目中多了个 lib 文件夹,并且里面的代码属于严格模式。因为是 build 文件,所以记得在 .gitignore 添加 lib

添加单元测试用例

往往我们开始学习 babel 都是因为有实际需求才会学习,所以打通单元测试,提前编写好单元测试场景,是有必要的。

  1. 添加测试框架,这里我采用的是 mocha ,属于 assert 断言,比较老的框架,2011年发布的。大家可以尝试其他的框架,大同小异。
  2. 添加测试框架依赖,yarn add -D mocha mochawesome  or npm install --save-dev mocha mochawesome  。
  3. mochawesome 是可以导出 html 格式的报表。
  4. .gitignore 添加一下 mochawesome 的输出文件夹 mochawesome-report 
  5. 在根目录创建测试用例文件夹 test ,并创建文件 index.js 。
  6. test 里面创建文件夹 fixtures 存储测试用例,然后开始创建第一个测试单元,在 fixtures 里面创建文件夹 one ,并在 one 文件夹里面创建文件 。如图

image.png

  1. actual.js 是 babel 处理前的源代码, expected.js 是经过 babel 插件处理后的预期代码。这个 .babelrc 是单独配置测试单元的。

actual.js

var a = 1;
var b = 1;
if (a === b) {
  console.log(1);
}

expected.js

var a = 1;
var b = 1;

if (left === right) {
  console.log(1);
}

.babelrc 

{
    "plugins": [
      "../../../lib"
    ]
}
  1. 编写测试用例校验
import path from 'path';
import fs from 'fs';
import assert from 'assert';
import { transformFileSync } from '@babel/core';
import * as parser from '@babel/parser';
import traverse from '@babel/traverse';
import * as t from '@babel/types'
import * as babylon from 'babylon';

function trim(str) {
  return str.replace(/^\s+|\s+$/, '');
}

describe('测试用例目录', () => {
  const fixturesDir = path.join(path.resolve(), 'test', 'fixtures');
    before(() => {
      console.log(`---开始读取测试用例文件夹 - ${fixturesDir}`)
    })
    after(() => {
      console.log(`---结束读取测试用例文件夹 - ${fixturesDir}`)
    })
  fs.readdirSync(fixturesDir).map((caseName) => {
    const fixtureDir = path.join(fixturesDir, caseName);
    const actualPath = path.join(fixtureDir, 'actual.js');

    beforeEach(function(){
      console.log(`-----测试用例 - ${fixtureDir}`);
    })

    it(`should ${caseName.split('-').join(' ')}`, () => {
      const actual = transformFileSync(actualPath).code;
      const expected = fs.readFileSync(
          path.join(fixtureDir, 'expected.js')
      ).toString();
      assert.equal(trim(actual), trim(expected));
    })
  });
});

  1. 添加对应工具集依赖, yarn add -D @babel/traverse @babel/parser @babel/register 。
  2. package.json 的 scripts 里添加指令
  "scripts": {
    "build": "babel src -d lib",
    "report": "npm run build && mocha --reporter mochawesome --require @babel/register",
    "test": "npm run build && mocha --require @babel/register",
    "test:watch": "npm run build && npm run test -- --watch"
  }
  • report - 测试报告,通过报告可以交付测试场景。
  • test:watch - 监听测试,可以持续性编写修改单元测试用例。
  1. 运行 test 和 report 看看能否正常运行。

总结

通过一个简单的 demo 走通工程化的 babel plugin 编写流程。大致掌握 babel 插件的开发流程,再去深入学习对应环节的知识,比如各种断言库、各种 node 测试框架、各种场景的 babel 支持配置等。 后续只要通过更改 src 里的源码,和添加测试用例,就可以不断趋向于一款正经的 babel plugin