Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using babel-register in my cli npm app works locally, but not globally after publish

I have developed a javascript CLI app that is using ES2015 code with babel as compiler. (babel-require hook)

The app works perfectly locally, but when I publish on npm, it stops working (babel does not seem to compile the ES2015 files anymore)

Setup:

sample ./bootstrap.js (ES5):

require('babel-register');
require('./src/app.js');

sample ./src/app.js (ES2015):

import package from 'package';
...

sample ./bin/myapp:

#!/usr/bin/env node
require('../bootstrap.js');

Running locally works:

appdir$ ./bin/myapp
I'm running fine!
appdir$

Running globally (after npm install) breaks:

$ sudo npm install -g myapp
└── [email protected]
$ myapp
/usr/local/lib/node_modules/myapp/src/app.js:1
(function (exports, require, module, __filename, __dirname) { import package from 'package';
                                                              ^^^^^^

SyntaxError: Unexpected token import
    at exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:404:25)
    at Module._extensions..js (module.js:432:10)
    at Object.require.extensions.(anonymous function) [as .js] (/usr/local/lib/node_modules/myapp/node_modules/babel-register/lib/node.js:138:7)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:313:12)
    at Module.require (module.js:366:17)
    at require (module.js:385:17)
    at Object.<anonymous> (/usr/local/lib/node_modules/myapp/server.js:9:12)
    at Module._compile (module.js:425:26)   

Versions:

    ├─┬ [email protected]
    │ │ ├─┬ [email protected]
    │ │ │ ├─┬ [email protected]
    │ │ │ ├─┬ [email protected]
    │ │ │ ├── [email protected]
    │ │ ├── [email protected]

What I have tried:

  • Adding ignore: false in my .babelrc file hoping it would enable compilation
  • using options in require hook arguments instead of .babelrc file

No luck :/

like image 654
Pandaiolo Avatar asked Jan 31 '16 22:01

Pandaiolo


People also ask

What does Babel Register do?

@babel/register uses Node's require() hook system to compile files on the fly when they are loaded. While this is quite helpful overall, it means that there can be confusing cases where code within a require() hook causes more calls to require , causing a dependency cycle.

Should I use Babel production?

Not meant for production useYou should not be using babel-node in production. It is unnecessarily heavy, with high memory usage due to the cache being stored in memory. You will also always experience a startup performance penalty as the entire app needs to be compiled on the fly. Check out the example Node.

Do you need Babel for node?

And many frameworks today use Babel under the hood to compile their code. For example, Node can't use ES6 import and export statements and some other cool features of ES6 syntax without the help of a compiler like Babel.

How do you run JS in Babel?

Simply add a "scripts" field to your package. json and put the babel command inside there as build . This will run Babel the same way as before and the output will be present in lib directory, only now we are using a local copy. Alternatively, you can reference the babel cli inside of node_modules .


1 Answers

Ok, I figured out what was the issue. I was on the right track thinking there was something forbidding the compilation to happen.

TL;DR

babel-register hook does not take ignore and only options from the .babelrc file, but it does from its arguments.

The fix in ./bootstrap.js:

require('babel-register')({
  ignore: [],
  only: [/src/],
});
require('./src/app.js');
  • The ignore switch will disable ignoring files which match node_modules in their path, which is the case for every global module.
  • The only switch then enables compilation of the files of my project src directory.

Now, if you're interested, I will describe the steps I took to resolve the issue, because I think I did it right (this time :))...

Story of the troubleshooting:

  • First, I needed to install node-debug commandline tool

    $ sudo npm install -g node-inspector
    
  • Then launch my app with it (--debug-brk switch asks to stop execution at first line)

    $ node-debug --debug-brk myapp
    
  • Open my browser at the local URL provided by node-debug, and voila see my app code

  • Place a breakpoint the line just above the require('./scr/app.js'); statement
  • Click 'play' to continue process execution until that line
  • Here starts the tedious task of climbing the error trace using 'step over' and 'step inside' buttons : when the next statement is 'outside' of your error trace (see the one above in the question), I could 'step over'. If the next statement is one of the functions of the trace, 'step in'.
  • I then realized, by looking at the 'scope variable' watches, when in the Object.require.extension method, in file babel-register/lib/node.js, that ignore and only variables were undefined, despite I wanted them to be defined!
  • I stepped inside the method shouldIgnore of the same file, which confirmed my fears : this function checks for node_modules in the path, if !ignore && !only and returns true (ignore file) if it matches. This is ultimately what caused my ES2015 files to not compile.

    babel-register/lib/node.js:120:
    function shouldIgnore(filename) {
      if (!ignore && !only) {  // here `ignore` and `only` were null, despite .babelrc values
        return getRelativePath(filename).split(_path2["default"].sep).indexOf("node_modules") >= 0;
      } else {
        return _babelCore.util.shouldIgnore(filename, ignore || [], only);
      }
    }
    
  • I then guessed that I would have to specify thoses switches directly in babe-register arguments.

like image 108
Pandaiolo Avatar answered Sep 30 '22 19:09

Pandaiolo