Babel插件中的“ Visitor.Program.enter()”和“ pre()”有什么区别?

时间:2018-10-18 09:00:46

标签: node.js babeljs visitor babel-plugin

此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 / { {1}}?

有什么区别吗?

2 个答案:

答案 0 :(得分:2)

AFAIK没有区别。完全遍历语法树之前/之后都调用它们。

唯一的区别是传递给@user.article.description / 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则没有访问权限。

答案 1 :(得分:0)

prepost有更根本的用途:它们在所有遍历之前/之后针对所有插件运行。 所有插件的顺序是:

  1. pre为所有插件运行
  2. visitor为所有插件运行
  3. post为所有插件运行。

要回答您的问题:visitor.Program.enterpre在大多数情况下的行为相同,也就是说,如果您不关心当时其他插件是否已经开始访问Program您自己的插件的visitor开始。主要区别可以概括为两点:

    确保
  1. pre任何插件开始遍历之前运行。
  2. 确保
  3. pre只能运行一次,而节点访问者可以运行多次,因为(您自己或其他插件的)访问者对AST进行的更改可能会无限期地运行再次访问的数量。

插件(和预设)的执行顺序

请注意,插件的执行顺序是一个尚未解决的悬而未决的问题(see here for a first introduction),prepost有助于减轻可能会发生冲突的插件的某些痛苦与其他插件。

作为参考,这是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之后运行,尽管according to the docs on plugin orderingpresets应该在plugins之后运行。但是,as explained here实际上并不是那么简单:所有插件和预设都可以并行遍历,而docs中描述的顺序(预设之前的插件)仅针对每个节点(而不是整个AST遍历)得到保证。