简体   繁体   中英

How to write a babel js plugin that passes output to other plugins?

I'm trying to write a babel plugin that prepends/appends content to a file - for example; add the lines console.log("start of " + __filename); and console.log("end of " + __filename); to each file.

So far, I've managed to write a visitor that does exactly this, however the existing code doesn't get modified by any other plugins before OR after my plugin operates.

For example, I have the following file:

import * as foo from 'foo';
import * as bar from 'bar';

console.dir({ foo, bar });

Using the env preset alone (ie. without my plugin) and the option targets.node: 'current' I end up with the output - note that es6 imports have been transformed into commonjs requires:

'use strict';
var _foo = require('foo');
var foo = _interopRequireWildcard(_foo);
var _bar = require('bar');
var bar = _interopRequireWildcard(_bar);
function _interopRequireWildcard(obj) { /* resolve commonjs or es6 module */ }
console.dir({ foo, bar });

However as soon as I add my own plugin to this; it appears that the env preset is skipped in favour of my own plugin - however I'd like both plugins to be applied (mine first, preferably).


So far, my plugin code looks like:

module.exports = function wrapModule(babel) {

  const prepend = transform(`console.log("start of " + __filename);`)
  const append = transform(`console.log("end of " + __filename);`)
  return {
    visitor: {
      Program(path, {opts}) {
        path.replaceWith(t.program([...prepend, ...path.node.body, ...append]))
        path.stop()
      }
    }
  }

  function transform(content) {
    return babel.transform(content).ast.program.body
  }
}

and my .babelrc is simply:

{
  "presets": [[
    "env", { "targets": { "node": "current" } }
  ]],
  "plugins": [
    "./wrapper-babel-plugin"
  ]
}

And this is producing the output:

console.log("start of " + __filename);
import * as foo from 'foo';
import * as bar from 'bar';

console.dir({ foo, bar });
console.log("end of " + __filename);

Can anyone suggest what I'm missing to have babel chain my plugin with other plugins, to allow me to use multiple plugins in combination?

And this is producing the output:

Given that you are using eval , and you are calling your transform function with the wrong number of arguments, that can't possibly be true :)

The correct way to write what you're looking for would be

export default function wrapModule({ template }) {
  const prepend = template(`console.log("start of " + __filename);`);
  const append = template(`console.log("end of " + __filename);`);

  return {
    visitor: {
      Program(path, {opts}) {
        path.unshiftContainer("body", prepend());
        path.pushContainer("body", append());
      }
    }
  };
}

By using unshiftContainer and pushContainer Babel can queue up those nodes for processing by other plugins. This also uses template to generate the ASTs for your two snippets.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM