There is a more fundamental use to pre
and post
: they run for all plugins before/after all traversals. The order for all plugins is:
pre
runs for all plugins
visitor
runs for all plugins
post
runs for all plugins.
To answer your question: visitor.Program.enter
and pre
behave the same in most cases, that is, if you don't care if other plugins have already started visiting Program
by the time your own plugin's visitor
starts. The main difference can be summed up in two points:
pre
is ensured to run before any plugin started traversal.
pre
is ensured to only ever run once, while node visitors can run many times, as changes to the AST by (your own or other plugins') visitors might warrant an indefinite amount of re-visits.
Execution order of plugins (and presets)
Note that execution order of plugins is an open problem that is heavily discussed (see here for a first introduction), and pre
and post
help alleviate some of that pain for plugins that can potentially can collide with other plugins.
For reference, this is the execution order of plugins and presets in Babel7 (when run with the babel.config.js
given below):
[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
Reference 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
]
};
Discussion: Babel plugin execution order confusion
I was rather confused myself, when I wrote my first plugin. It seemed to run after @babel/preset-env
, even though, according to the docs on plugin ordering, presets
should run after plugins
. However, as explained here, it is actually not that simple: all plugins' and presets' visitors
traverse in parallel, while the order described in the docs (plugins before presets) is only ensured for each node individually, not for the entire AST traversal. That pain point is the main motivation for pre
and post
.