В чем разница между "Visitor.Program.enter()" и "pre()" в плагине Babel?
Этот плагин Babel:
module.exports = function(){
return {
visitor:{
Program:{
enter(){ console.log('Enter') },
exit(){ console.log('Exit') }
}
},
pre(){ console.log('Pre') },
post(){ console.log('Post') }
}
}
производит этот вывод для любого файла JavaScript:
Pre
Enter
Exit
Post
pre()
называется прямо перед Program.enter()
а также post()
сразу после Program.exit()
,
Если я хочу запустить некоторый код в начале / конце обхода AST, есть ли причина, по которой я должен поместить этот код внутрь pre
/post
вместо Program.enter
/Program.exit
?
Есть ли какая-то разница?
0 ответов
Там нет разницы AFAIK. Оба вызываются до / после того, как синтаксическое дерево было полностью пройдено.
Единственное отличие состоит в том, что параметры передаются Program.enter
/Program.exit
отличаются от параметров, переданных pre
/post
,
module.exports = function(){
return {
visitor:{
Program:{
enter(path, state){
//path.node
//path.parent
//state.opts
},
}
},
pre(state){
//state.scope
//state.scope.globals
//state.scope.plugins
},
}
}
Например, из Program.enter()
у вас есть доступ к state.opts
с вашими опциями плагина, тогда как из pre()
ты не
Есть более фундаментальное применение pre
а также post
: они запускаются для всех плагинов до / после всех обходов. Порядок всех плагинов:
pre
работает для всех плагиновvisitor
работает для всех плагиновpost
работает для всех плагинов.
Чтобы ответить на ваш вопрос: visitor.Program.enter
а также pre
в большинстве случаев вести себя одинаково, то есть, если вам все равно, начали ли уже посещать другие плагины Program
к тому времени, когда ваш собственный плагин visitor
начинается. Основное отличие можно резюмировать двумя пунктами:
pre
гарантированно запускается до того, как любой плагин начнет обход.pre
гарантированно запускается только один раз, в то время как посетители узла могут запускаться много раз, поскольку изменения AST посетителями (вашими или другими плагинами) могут потребовать неограниченного количества повторных посещений.
Порядок выполнения плагинов (и пресетов)
Обратите внимание, что порядок выполнения плагинов - это открытая проблема, которая активно обсуждается (см. Здесь для первого введения), иpre
а также post
помочь облегчить часть этой боли для плагинов, которые потенциально могут конфликтовать с другими плагинами.
Для справки, это порядок выполнения плагинов и пресетов в Babel7 (при запуске с babel.config.js
нижеприведенный):
[PLUGIN] pre plugin1
[PLUGIN] pre plugin2
[PLUGIN] pre pres2
[PLUGIN] pre pres1
[PLUGIN] Program plugin1
[PLUGIN] Program plugin2
[PLUGIN] Program pres2
[PLUGIN] Program pres1
[PLUGIN] post plugin1
[PLUGIN] post plugin2
[PLUGIN] post pres2
[PLUGIN] post pres1
Ссылка babel.config.js
:
function makeReporterPlugin(msg) {
return () => {
return {
pre() {
console.log('[PLUGIN] pre', msg);
},
visitor: {
Program() {
console.log('[PLUGIN] Program', msg);
}
},
post() {
console.log('[PLUGIN] post', msg);
},
};
};
}
const pres1 = {
plugins: [
makeReporterPlugin('pres1')
]
};
const pres2 = {
plugins: [
makeReporterPlugin('pres2')
]
};
const plugin1 = makeReporterPlugin('plugin1');
const plugin2 = makeReporterPlugin('plugin2');
module.exports = {
"presets": [
pres1,
pres2
],
"plugins": [
plugin1,
plugin2
]
};
Обсуждение: путаница в порядке выполнения плагина Babel
Когда я писал свой первый плагин, я сам был несколько сбит с толку. Казалось, бежал за@babel/preset-env
хотя, согласно документации по заказу плагинов,presets
должен бежать за plugins
. Однако, как объясняется здесь, на самом деле это не так просто: все плагины и пресеты проходят параллельно, в то время как порядок, описанный в документации (плагины перед пресетами), гарантируется только для каждого узла индивидуально, а не для всего обхода AST.