什么是acorn与babel
在上一篇中,我使用的是babel的解析器实现的找出模块中导出的变量的值。我也特别介绍了,新版本的babel
底层换成了acorn
这个库。
那么,我们就用acorn
的相关库,实现同一个需求。
在上文中我已经提到了
@babe/parser
和@babel/traverse
这两个库,在下文中我以parser和traverse代指这两个库。在
acorn
中,以acorn
和walk
代指acorn
与acorn-walk
。
对应的,还是以下两种解法,解法一:
源码地址: https://github.com/stack-wuh/mini-cli/blob/main/core/babel-export/mixin.js
import fsp from 'fs/promises'
import * as acorn from 'acorn'
import * as walk from 'acorn-walk'
const filePath = './export.js'
/**
* @NOTE 这里是acorn版本的解析器
* @NOTE 对解析出来的AST对象进行取值
*/
const workflow = async () => {
const source = await fsp.readFile(filePath, { encoding: 'utf-8' })
const ast = acorn.parse(source, { sourceType: 'module' })
const { body } = ast
const exportNamed = {}
body.filter(node => node.type === 'ExportNamedDeclaration').forEach(node => {
const [head] = node.declaration.declarations
exportNamed[head.id.name] = true
})
console.log('======> workflow.exportNamed', exportNamed)
}
workflow()
解法二:
/**
* @NOTE 使用acorn解析ast
* @NOTE 使用acorn-walk 实现节点的遍历
*/
const workflowWithWalk = async () => {
const source = await fsp.readFile(filePath, { encoding: 'utf-8' })
const ast = acorn.parse(source, { sourceType: 'module' })
const exportNamed = {}
walk.simple(ast, {
ExportNamedDeclaration: node => {
const [head] = node.declaration.declarations
exportNamed[head.id.name] = true
}
})
console.log('=====> workflowWithWalk.exportNamed', exportNamed)
}
workflowWithWalk()
可以与babel
版本的代码相对比一下,其实差异真的不太大,无非了换了使用的库和api。
请注意,
acorn-walk
可以遍历任何 AST 树,不一定非要是 Acorn 创建的 AST。如果您仅需要遍历 AST树,或在没有Babel的情况下使用Acorn,那么使用Acorn-walk是一种很好的遍历器选择。
我们从官网上了解到了这一个AST的遍历器非常厉害,可以遍历一切AST对象。还记得我们上一篇中对比节点类型的表格吗?babel
和acorn
遍历的部分用到的节点类型是一样的,有一个非常好的例子就是Literal
,这个节点的类型不一样。
我们先试着用walk
去遍历由babel
解析出来的AST对象。果然,没那么简单,还是有兼容性的问题。还记得前面对照表里的Literal
吗?
在acorn
是Literal
,而在babel
里面是NumberLiteral
,可以去看下我的export.js
文件,里面声明了一个数字类型的变量是没有导出的,所以问题就是这两个解析器之间对字面量类型的解析token有兼容性问题。
注意
- 这里这个问题先放在这里,随着后面的学习,试着把这个问题解决一下;