原文链接:http://axuebin.com/articles/fe-solution/babel/auto-require.html,转载请联系
前言
最近在尝试玩一玩已经被大家玩腻的 Babel
,今天给大家分享如何用 Babel
为代码自动引入依赖,通过一个简单的例子入门 Babel
插件开发。
需求
const a = require('a');
import b from 'b';
console.log(axuebin.say('hello babel'));
同学们都知道,如果运行上面的代码,一定是会报错的:
VM105:2 Uncaught ReferenceError: axuebin is not defined
我们得首先通过 import axuebin from 'axuebin'
引入 axuebin
之后才能使用。。
为了防止这种情况发生(一般来说我们都会手动引入),或者为你省去引入这个包的麻烦(其实有些编译器也会帮我们做了),我们可以在打包阶段分析每个代码文件,把这个事情做了。
在这里,我们就基于最简单的场景做最简单的处理,在代码文件顶部加一句引用语句:
import axuebin from 'axuebin';
console.log(axuebin.say('hello babel'));
前置知识
什么是 Babel
简单地说,Babel
能够转译 ECMAScript 2015+
的代码,使它在旧的浏览器或者环境中也能够运行。我们日常开发中,都会通过 webpack
使用 babel-loader
对 JavaScript
进行编译。
Babel 是如何工作的
首先得要先了解一个概念:抽象语法树(Abstract Syntax Tree, AST),Babel
本质上就是在操作 AST
来完成代码的转译。
了解了 AST
是什么样的,就可以开始研究 Babel
的工作过程了。
Babel
的功能其实很纯粹,它只是一个编译器。
大多数编译器的工作过程可以分为三部分,如图所示:
- Parse(解析) 将源代码转换成更加抽象的表示方法(例如抽象语法树)
- Transform(转换) 对(抽象语法树)做一些特殊处理,让它符合编译器的期望
- Generate(代码生成) 将第二步经过转换过的(抽象语法树)生成新的代码
所以我们如果想要修改 Code
,就可以在 Transform
阶段做一些事情,也就是操作 AST
。
AST 节点
我们可以看到 AST
中有很多相似的元素,它们都有一个 type
属性,这样的元素被称作节点。一个节点通常含有若干属性,可以用于描述 AST
的部分信息。
比如这是一个最常见的 Identifier
节点:
{
type: 'Identifier',
name: 'add'
}
所以,操作 AST
也就是操作其中的节点,可以增删改这些节点,从而转换成实际需要的 AST
。
更多的节点规范可以查阅 https://github.com/estree/estree
AST 遍历
AST
是深度优先遍历的,遍历规则不用我们自己写,我们可以通过特定的语法找到的指定的节点。
Babel
会维护一个称作 Visitor
的对象,这个对象定义了用于 AST
中获取具体节点的方法。
一个 Visitor
一般是这样:
const visitor = {
ArrowFunction(path) {
console.log('我是箭头函数');
},
IfStatement(path) {
console.log('我是一个if语句');
},
CallExpression(path) {
},
};
visitor
上挂载以节点 type
命名的方法,当遍历 AST
的时候,如果匹配上 type
,就会执行对应的方法。
操作 AST 的例子
通过上面简单的介绍,我们就可以开始任意造作了,肆意修改 AST
了。先来个简单的例子热热身。
箭头函数是 ES5
不支持的语法,所以 Babel
得把它转换成普通函数,一层层遍历下去,找到了 ArrowFunctionExpression
节点,这时候就需要把它替换成 FunctionDeclaration
节点。所以,箭头函数可能是这样处理的:
import * as t from '@babel/types';
const visitor = {
ArrowFunction(path) {
path.