2

这个 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

它有什么不同吗?

4

2 回答 2

5

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

唯一的区别是传递给/ 的参数与传递给 /Program.enterProgram.exit参数不同。prepost

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()您不能。

于 2019-04-04T15:41:46.253 回答
1

pre和有一个更基本的用途post:它们在所有遍历之前/之后为所有插件运行。所有插件的顺序是:

  1. pre适用于所有插件
  2. visitor适用于所有插件
  3. post适用于所有插件。

回答您的问题:visitor.Program.enter并且pre在大多数情况下表现相同,也就是说,如果您不在乎其他插件Program在您自己的插件visitor启动时是否已经开始访问。主要区别可以总结为两点:

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

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

请注意,插件的执行顺序是一个被大量讨论的开放性问题(请参阅此处了解第一个介绍),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,尽管根据插件订购的文档presets应该在plugins. 但是,正如这里所解释的,实际上并不是那么简单:所有插件和预设的visitors遍历并行,而文档中描述的顺序(预设之前的插件)仅针对每个节点单独确保,而不是针对整个 AST 遍历。pre那个痛点是和的主要动机post

于 2019-12-06T10:13:52.347 回答