Say you have a file with:
AddReactImport();
Run Code Online (Sandbox Code Playgroud)
And the plugin:
export default function ({types: t }) {
return {
visitor: {
CallExpression(p) {
if (p.node.callee.name === "AddReactImport") {
// add import if it's not there
}
}
}
};
}
Run Code Online (Sandbox Code Playgroud)
How do you add import React from 'react'; at the top of the file/tree if it's not there already.
I think more important than the answer is how you find out how to do it. Please tell me because I'm having a hard time finding info sources on how to develop Babel plugins. My sources right now are: Plugin Handbook,Babel Types, AST Spec, this blog post, and the AST explorer. It feels like using an English-German dictionary to try to speak German.
export default function ({types: t }) {
return {
visitor: {
Program(path) {
const identifier = t.identifier('React');
const importDefaultSpecifier = t.importDefaultSpecifier(identifier);
const importDeclaration = t.importDeclaration([importDefaultSpecifier], t.stringLiteral('react'));
path.unshiftContainer('body', importDeclaration);
}
}
};
}
Run Code Online (Sandbox Code Playgroud)
如果要注入代码,只需使用@babel/template为其生成 AST 节点即可;然后根据需要注入它。
我也同意,即使在 2020 年,信息也很少。我得到了我的大部分信息的通过实际工作babel的源代码,看着所有的工具(types,traverse,path,code-frame等...),他们使用的帮手,现有插件(例如istanbul到有点了解的JS基本仪器), webpackbabel-loader和更多...
例如:(unshiftContainer实际上,babel-traverse一般来说)没有官方文档,但您可以在此处找到它的源代码(令人着迷的是,它接受单个节点或节点数组!)
在这种特殊情况下,我会:
@babel/templateProgram仅当找到特定的函数调用时才将其注入(即根路径)一次注意:模板也支持变量。如果您想包装现有节点或想根据上下文生成相同代码的轻微变化,则非常有用。
import template from "@babel/template";
// template
const buildImport = template(`
import React from 'react';
`);
// plugin
const plugin = function () {
const importDeclaration = buildImport();
let imported = false;
let root;
return {
visitor: {
Program(path) {
root = path;
},
CallExpression(path) {
if (!imported && path.node.callee.name === "AddMyImport") {
// add import if it's not there
imported = true;
root.unshiftContainer('body', importDeclaration);
}
}
}
};
};
Run Code Online (Sandbox Code Playgroud)
另一种选择是:
parseSource)生成 ASTProgram仅当找到特定的函数调用时才将其注入(即根路径)一次与上面相同,但使用您自己的编译器函数(效率不如@babel/template):
/**
* Helper: Generate AST from source through `@babel/parser`.
* Copied from somewhere... I think it was `@babel/traverse`
* @param {*} source
*/
export function parseSource(source) {
let ast;
try {
source = `${source}`;
ast = parse(source);
} catch (err) {
const loc = err.loc;
if (loc) {
err.message +=
"\n" +
codeFrameColumns(source, {
start: {
line: loc.line,
column: loc.column + 1,
},
});
}
throw err;
}
const nodes = ast.program.body;
nodes.forEach(n => traverse.removeProperties(n));
return nodes;
}
Run Code Online (Sandbox Code Playgroud)
Set)。@babel/template)的节点实际上是副本,而不是原始节点。在这种情况下,您要记住它已被检测并跳过它以防您再次遇到它,或者再次:无限循环!loc属性来跳过它们(注入的节点通常没有loc财产)。import语句,如果没有启用正确的插件或没有将程序类型设置为module.| 归档时间: |
|
| 查看次数: |
2636 次 |
| 最近记录: |