- 打算重构一款旧的 babel 插件,所以想着记录一下整个过程,让更多的人能快速学习 babel 插件的搭建。
- 也会有些工程化理念。
搭建
- 新建文件夹
- 使用工具初始化项目,指令
yarn initornpm init - 添加
.gitignore文件,并在里面写上node_modules - 在项目文件夹中,创建文件夹
src,src主要存储源码。 - 在
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 -Dornpm install --save-dev @babel/cli @babel/core @babel/preset-env - 在
.babelrc文件添加
{
"presets": ["@babel/preset-env"]
}
- 运行 build 指令,
yarn buildornpm run build
可以看项目中多了个 lib 文件夹,并且里面的代码属于严格模式。因为是 build 文件,所以记得在 .gitignore 添加 lib。
添加单元测试用例
往往我们开始学习 babel 都是因为有实际需求才会学习,所以打通单元测试,提前编写好单元测试场景,是有必要的。
- 添加测试框架,这里我采用的是
mocha,属于 assert 断言,比较老的框架,2011年发布的。大家可以尝试其他的框架,大同小异。 - 添加测试框架依赖,
yarn add -D mocha mochawesomeornpm install --save-dev mocha mochawesome。 - mochawesome 是可以导出 html 格式的报表。
- 在
.gitignore添加一下 mochawesome 的输出文件夹mochawesome-report - 在根目录创建测试用例文件夹
test,并创建文件index.js。 - 在
test里面创建文件夹fixtures存储测试用例,然后开始创建第一个测试单元,在fixtures里面创建文件夹one,并在 one 文件夹里面创建文件 。如图
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"
]
}
- 编写测试用例校验
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));
})
});
});
- 添加对应工具集依赖,
yarn add -D @babel/traverse @babel/parser @babel/register。 - 在
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 - 监听测试,可以持续性编写修改单元测试用例。
- 运行 test 和 report 看看能否正常运行。
总结
通过一个简单的 demo 走通工程化的 babel plugin 编写流程。大致掌握 babel 插件的开发流程,再去深入学习对应环节的知识,比如各种断言库、各种 node 测试框架、各种场景的 babel 支持配置等。 后续只要通过更改 src 里的源码,和添加测试用例,就可以不断趋向于一款正经的 babel plugin。