Search code examples
javascriptwebpackgruntjsbabeljsprecompile

Use webpack or node.js compiler to wrap all functions and methods


The technology for this must be available I'm just not sure how to hook it up. This is not intended to use in production, so I understand the effect it will have on performance, this mostly just an idea about debugging I'm working through. This would be for all or some files in a project, not just a single file.

I want to:

  1. Use a precompiler, like webpack or grunt, I don't want it in the actual files.
  2. Locate all functions/methods. (Prototypes methods would be nice as well)
  3. Wrap these functions with a simple function.

A simple example would be:

INPUT:

const obj = {
    func: function(){return 'obj.Func'}
};

function B(a,b,c){
    const innerFunc = (e,f,g)=>{
        return 'innerFunc'
    };
    return
}

---- Runs through complier ---

OUTPUT:

    const wrapper = (arguments,cb)=>{
        // Spread arguments etc.
        // this is pseudo code but you get the idea
        console.log('Hey this function ran!')
        return cb(arguments[0],arguments[1],arguments[2]);
    }

    const obj = {
        func: function(){return wrapper(arguments,()=>{ return 'obj.Func'})}
    };

    function B(a,b,c){
        return wrapper(arguments,(a,b,c)=>{
            const innerFunc = (e,f,g)=>{
                return wrapper(arguments,(e,f,g)=>{
                    return 'innerFunc
                });
            };
        });
    }

I'm just not quite sure where to look to try to do this. I guessing that Babel already identifies everything like this, as well as eslint etc.


Solution

  • This is not a problem with a quick solution, and I suspect there are many pitfalls and subtleties that I haven't even begun to cover here, so very much consider this a nudge in the right direction rather than a full solution.

    First you will need to read

    https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md

    Then you will create a Babel transformer that looks a bit like this.

    module.exports = function transform(babel) {
      const t = babel.types;
      return {
        visitor: {
          FunctionDeclaration(path) {
            // you will use const t as defined above in here to
            // create your wrapper and manipulate the current method.
            // It essentially gives you access to babel types.
            // The path variable allows you get meta data about the function
            // and dive deeper into it.
          }
        }
      }
    }
    

    The important bit is that the visitor works on 'FunctionDeclaration' - that is the method/function blocks that you're looking to change. You would then replace the function with a new identifier that would wrap the original method as you have specified in your question.

    This is known as a loader, and you will need to add it into your webpack config with any other loaders you may be using. It will manipulate your code before it is bundled by webpack.


    It may be easier just to inject whatever you want your 'wrapper' code to do directly into each function. For intance if you just want to console.log the function name whenever it is run, this transformer will achieve that:

    module.exports = function transform(babel) {
      const t = babel.types;
      return {
        visitor: {
          FunctionDeclaration(path) {
            const args = [t.stringLiteral(`${path.node.id.name} called`)];
            const expression = t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('log')), args);
            path.get('body').unshiftContainer('body', expression);
          }
        }
      }
    }
    

    This will convert:

    function bobbins(arg1, arg2) {
      return arg1 + arg2;
    }
    

    to

    function bobbins(arg1, arg2) {
      console.log("bobbins called");
      return arg1 + arg2;
    }