如果你还没有听说过。 babel-plugin-macros"启用零配置、可导入的babel插件"。几个月前,我在babel官方博客上发表了一篇关于它的博文。"使用babel-plugin-macros的零配置代码转换"。
从那时起,就有了一些令人兴奋的发展。
到目前为止,虽然有相当多的人在使用越来越多的现有宏,但只有早期采用者才尝试编写宏。你可以用babel-plugin-macros ,有很多了不起的事情可以做,我想用这篇简讯来告诉你如何开始玩写自己的宏。
让我们从一个精心设计的宏开始,它可以分割一串文本,并用🐶 替换每个空格。我们把它叫做gemmafy ,因为我的狗的名字是 "Gemma"。汪!
- 转到astexplorer.net
- 确保语言被设置为
JavaScript - 确保分析器被设置为
babylon7 - 启用转换,并将其设置为
babel-macros(或在合并后尽快设置为babel-plugin-macros)。
然后在源码(左上角)代码面板中复制/粘贴这个:
import gemmafy from 'gemmafy.macro'
console.log(gemmafy('hello world'))
并在转换(左下角)代码面板中复制/粘贴这个:
module.exports = createMacro(gemmafyMacro)
function gemmafyMacro({references, state, babel}) {
references.default.forEach(referencePath => {
const [firstArgumentPath] = referencePath.parentPath.get('arguments')
const stringValue = firstArgumentPath.node.value
const gemmafied = stringValue.split(' ').join(' 🐶 ')
const gemmafyFunctionCallPath = firstArgumentPath.parentPath
const gemmafiedStringLiteralNode = babel.types.stringLiteral(gemmafied)
gemmafyFunctionCallPath.replaceWith(gemmafiedStringLiteralNode)
})
}
或者,你也可以打开这个
TADA 🎉!你已经通过一个宏编写了你的(可能是)第一个babel插件
这是你应该看到的输出(在右下角面板):
console.log('hello 🐶 world')
你会注意到,babel-plugin-macros 会帮你删除文件顶部的导入,而我们的宏用字符串替换了gemmafy 的调用。
所以这是你的挑战,尝试添加这个:
console.log(gemmafy('hello world', 'world goodbye'))
现在,这将转译为:
console.log('hello 🐶 world')
你的任务是让它改成这样:
console.log('hello 🐶 world', 'goodbye 🐶 world')
从这里开始,你可以用它来做很多有趣的事情。
如果你想看到更多的功能,那么在源码中复制这个(左上角):
import myMacro, {JSXMacro} from 'AnyNameThatEndsIn.macro'
// (note: in reality, the AnyNameThatEndsIn.macro should be the name of your package
// for example: `codegen.macro`)
const functionCall = myMacro('Awesome')
const jsx = Hi!
const templateLiteral = myMacro`hi ${'there'}`
literallyAnythingWorks(myMacro)
并在转换(左下)代码面板中复制/粘贴这个:
module.exports = createMacro(myMacro)
function myMacro({references, state, babel}) {
// `state` is the second argument you're passed to a visitor in a
// normal babel plugin. `babel` is the `@babel/core` module.
// do whatever you like to the AST paths you find in `references`.
// open up the console to see what's logged and start playing around!
// references.default refers to the default import (`myMacro` above)
// references.JSXMacro refers to the named import of `JSXMacro`
const {JSXMacro = [], default: defaultImport = []} = references
defaultImport.forEach(referencePath => {
if (referencePath.parentPath.type === 'TaggedTemplateExpression') {
console.log(
'template literal contents',
referencePath.parentPath.get('quasi'),
)
} else if (referencePath.parentPath.type === 'CallExpression') {
if (referencePath === referencePath.parentPath.get('callee')) {
console.log(
'function call arguments (as callee)',
referencePath.parentPath.get('arguments'),
)
} else if (
referencePath.parentPath.get('arguments').includes(referencePath)
) {
console.log(
'function call arguments (as argument)',
referencePath.parentPath.get('arguments'),
)
}
} else {
// throw a helpful error message or something :)
}
})
JSXMacro.forEach(referencePath => {
if (referencePath.parentPath.type === 'JSXOpeningElement') {
console.log('jsx props', {
attributes: referencePath.parentPath.get('attributes'),
children: referencePath.parentPath.parentPath.get('children'),
})
} else {
// throw a helpful error message or something :)
}
})
}
接下来,打开你的开发者控制台,看看控制台的日志。玩得开心点!
或者,你可以直接去这里
我认为我们可以利用这项技术去很多非常酷的地方。我没有在这篇简讯中花任何时间谈论宏背后的原因或给你一些想法。下面我将链接到一些想法的资源。基本的想法是,如果有一种方法可以预先编译你的一些操作,那么你就可以改善你的应用程序的运行时性能/捆绑大小。此外,这允许你在构建时做一些事情,因为你可以访问文件系统。这种可能性真的是无穷无尽的,而我们才刚刚开始呢好好享受吧!