Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using babel, how can I append some code to the top of every file?

My goal is to fake out getting some requirejs code working via babel. I've found that if I add the following: if (typeof define !== "function") { var define = require("amdefine")(module); } to the top of every file while running in nodejs things seem to work out.

Here is some code I wrote, which I thought would work or nearly work:

function injectDefine(babel) {
    var header = 'if (typeof define !== "function") { var define = require("amdefine")(module); }';

    return new babel.Plugin('amdefine', {
        visitor: {
            Program: {
                enter: function(path, file) {
                    path.unshiftContainer(
                        'body',
                        babel.types.expressionStatement(
                            babel.types.stringLiteral(header)
                        )
                    );
                },
            },
        },
    });
}

require('babel-core/register')({
    stage: 0,
    plugins: [{transformer: injectDefine}],
});

require('../components/button');

The components/button file is just me trying to test that some file can load.

Other notes: I'm using babel 5, and I can't upgrade right now. I also can't use a .babelrc very easily right now.

like image 241
Parris Avatar asked May 10 '16 20:05

Parris


2 Answers

Tip 1: the environment variable BABEL_DISABLE_CACHE=1 is needed if you are doing heavy testing of plugins. If you had a script that you ran like npm run unit you may instead want to run like BABEL_DISABLE_CACHE=1 npm run unit while testing your plugin.

Tip 2: babel.parse will give you a full program out of some source. The easiest thing you could do is babel.parse(header).program.body[0].

The following ended up working:

function injectDefine(babel) {

    var header = 'if (typeof define !== "function") { var define = require("amdefine")(module); }';

    return new babel.Plugin('amdefine', {
        visitor: {
            Program: {
                enter: function(node, parent) {
                    node.body.unshift(
                        babel.parse(header).program.body[0]
                    );
                },
            },
        },
    });
}

require('babel-core/register')({
    cache: false,
    stage: 0,
    plugins: [injectDefine],
});
like image 99
Parris Avatar answered Oct 06 '22 15:10

Parris


At this stage, a cleaner solution can be to use @babel/traverse and @babel/types.

Let's suppose you want to append a comment to the top of every file, you could use some code like the following:

// Import the required modules
import * as t from "@babel/types";
import traverse from "@babel/traverse";

// Get your ast (for this, you can use @babel/parser)

// Traverse your ast
traverse(ast, {
  // When the current node is the Program node (so the main node)
  Program(path) {
    // Insert at the beginning a string "Hello World" --> not valid JS code
    path.unshiftContainer('body', t.stringLiteral("Hello World"));
  }
});
like image 37
quirimmo Avatar answered Oct 06 '22 16:10

quirimmo