Using babel-register in my cli npm app works local

2019-02-10 11:13发布

问题:

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
└── myapp@0.1.0
$ 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:

    ├─┬ babel-register@6.4.3
    │ │ ├─┬ babel-core@6.4.5
    │ │ │ ├─┬ babel-code-frame@6.3.13
    │ │ │ ├─┬ babel-generator@6.4.5
    │ │ │ ├── babel-helpers@6.4.5
    │ │ ├── babel-runtime@5.8.35

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 :/

回答1:

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: false,
  only: /myapp\/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.