从webpack-route-plugin来了解babel
一、 插件babel相关源码分析
插件地址: github.com/hxfdarling/…
webpack-route-plugin相对其他自动路由插件比较有意思,它的核心思路操作ast,从每个文件的ast中判断是否有 export const routes =[],如果有将ast抽离出来加入 componentNode, 生成route 数据写入文件中, 这里只展示与ast相关的逻辑,
parseFilesToNodes.ts
function getRouterNode({ code, file, baseDir, routeFile }) {
// 获取router的值 -- 生成的是每个文件的路径
const routeFunction = arrowFunctionExpression(
[],
callExpression(identifier('import'), [ stringLiteral('.' + path.sep + path.relative(baseDir, file)), ]),
);
//生成componentast
const componentNode = objectProperty(identifier('component'), routeFunction);
...
...
// 判断是否有 export const routes =[]
const routesDeclaration = body.find(node => {
if (
isExportNamedDeclaration(node) &&
isVariableDeclaration(node.declaration) &&
isVariableDeclarator(node.declaration.declarations[0]) &&
[ROUTES_KEY, ROUTE_KEY].indexOf(
(node.declaration.declarations[0].id as Identifier).name,
) >= 0 &&
isArrayExpression(node.declaration.declarations[0].init)
) {
return true;
}
return false;
});
...
....
return toArray(router)
.map(node => {
if (isObjectExpression(node)) {
if (!isRedirect(node.properties)) {
...
...
...
//将生成的componentNode添加到每个抽离的router ast中
node.properties.push(componentNode);
}
return node;
} else {
console.warn('route item must is pure object:', node);
}
})
.filter(Boolean);
}
genCode.ts
...
...
//生成 const routes = [] 的整个路由数据
function genRoutesCode(nodes, outputFile) {
const ast = file(
program([
variableDeclaration('const', [
variableDeclarator(identifier(ROUTES_KEY), arrayExpression(nodes)),
]),
]),
'',
'',
);
return transformFromAstSync(ast, '', { filename: outputFile }).code;
}
genFile.ts
...
...
//将生成的路由数据写入文件
export default (options: RouteOptions | BootstrapOptions) => {
fs.writeFileSync(options.outputFile, genBootstrapCode(options));
return options.outputFile;
};
二、babel入门
developer.mozilla.org/zh-CN/docs/…
上面的链接各位大牛都写得相当详细,就不用在码字了,简单写写我的学习过程:
esprima.org/demo/parse.… 这个地址是javascript在线转化工具,刚开始接触ast比较蒙,无从下手,通过在线转化可以直观的看到javascript转化成每个节点对应什么,比如:
js
var answer = 6 * 7;
ast
{
"type": "Program",
"body": [
{
"type": "VariableDeclaration",
"declarations": [
{
"type": "VariableDeclarator",
"id": {
"type": "Identifier",
"name": "answer"
},
"init": {
"type": "BinaryExpression",
"operator": "*",
"left": {
"type": "Literal",
"value": 6,
"raw": "6"
},
"right": {
"type": "Literal",
"value": 7,
"raw": "7"
}
}
}
],
"kind": "var"
}
],
"sourceType": "script"
}
比如"type": "VariableDeclaration",
在 developer.mozilla.org/zh-CN/docs/…
可以查询到 相关的节点类型的具体用处
variableDeclaration(kind, dtors[, loc])
kind: "const" | "let" | "var"
dtors: [ CustomDeclarator ]
loc: SourceLocation
返回: CustomDeclaration
可以查询到babel types使用api那些api可以生成相对应的ast
variableDeclaration
t.variableDeclaration(kind, declarations)
See also t.isVariableDeclaration(node, opts) and t.assertVariableDeclaration(node, opts).
Aliases: Statement, Declaration
kind: "var" | "let" | "const" (required)
declarations: Array<VariableDeclarator> (required)
declare: boolean (default: null)
上述流程对应到webpack-route-plugin的逻辑中就是下面声明router的ast代码
function genRoutesCode(nodes, outputFile) {
const ast = file(
program([
variableDeclaration('const', [
variableDeclarator(identifier(ROUTES_KEY), arrayExpression(nodes)),
]),
]),
'',
'',
);
return transformFromAstSync(ast, '', { filename: outputFile }).code;
}
也许这个办法比较笨,但是我确实找不到好的有效的办法,通过分析javascript生成的ast节点,多写写,多看看,后面在看ast就相对来说好一点