How does mocha / babel transpile my test code on the fly?

旧时模样 提交于 2019-12-12 14:26:10

问题


My question is not about why something is not working, but rather why it is. Yes.

I have a small nodeJS command line tool, which contains features that nodeJS does not yet support out of the box, most notably:

  • import statements
  • String.includes().

Thus for delivery(build) I transpile+bundle my source code (using parcel, just like webpack).

As a positive wonder, all (but one) of my mocha tests run directly against my classes, not the bundle. Still, they work! Including many import statements. And including an 'ES6 self-test':

it( 'String - include', () => {
    var s = 'Southern Bananas'
    assert( s.includes( 'anana' ) )
    assert( !s.includes( 'kiwi' ) )
} )

Thus:

I have String.include in my test code, not just in the source under test. And there is no place where I transpile or bundle my test code… Thus apologies for my dumb question:

Why is this working? Is there a secret just-in-time compilation somewhere? (and if yes, could I use that for a debug flavour of my deliverable code-under-test as well?)

my mocha.opts are rather simple:

--require @babel/register
--require ./test/once.js  (nothing special here, either)
--reporter list
--recursive

my .babelrc has this:

{
    "presets": [
        [
            "@babel/preset-env",
            {
                "targets": {
                    "Electron": "3.0",
                    "Node": "8.0"
                }
            }
        ]
    ],
    "plugins": [
        "@babel/plugin-transform-runtime"
    ],
    "retainLines": true,
    "comments": false,
    "sourceMaps": true
}

@babel/plugin-transform-runtime is apparently not to blame praise, as it explicitly states

NOTE: Instance methods such as "foobar".includes("foo") will not work since that would require modification of existing built-ins (you can use @babel/polyfill for that).

Is @babel/polyfill contained in the minimalistik-modern afaik @babel/preset-env? What else an I doing right :+)? Is there a way to use this live compilation for my (debug) build as well?


回答1:


Long story short

String.prototype.includes is supported by Node.js since v6.5. @babel/register is causing your code to be compiled on the fly, that's why your import statements work. I doubt you need the @babel/plugin-transform-runtime plugin, unless I'm missing something that you're trying to achieve.

What can cause this confusion?

I think there are two root causes to this (totally understandable) mystery:

  1. The Babel authors have made it really easy to use the tool; and sometimes it is hard to know how/when it is being invoked (especially when paired with another tool like Mocha).
  2. What is/isn't supported natively by Node.js (in terms of ES2015, ES2016, etc.) has traditionally been hard to keep up with.

So, on to the two mysteries.

Why does String.prototype.includes work?

This one has the easier explanation. String.prototype.includes has been supported natively since as early as Node.js v6.5 (as you can see, a vast majority of ES2015 support has been supported since that version).

So, while you're correct that you don't have @babel/polyfill configured (as far as I can tell) and that you would need it in an environment that doesn't support String.prototype.includes, your environment already supports it!

From a Node.js v8.x REPL:

> 'ES2015'.includes('2015')
true

Why does your import statement work?

As you've stated, Node.js v8.x does not natively support ECMAScript Modules. However, there are some good write ups about how it has been enabled as an experimental feature starting in Node.js v9.x.

So, you get the following with native Node.js v8.x (via REPL):

> import path from 'path';
import path from 'path';
^^^^^^

SyntaxError: Unexpected token import

The reason your imports are working is because your code is being compiled by Babel using the @babel/preset-env preset. Furthermore, that compilation is being triggered by your --require @babel/register Mocha option.

@babel/register works by "bind[ing] itself to node's require and automatically compile files on the fly".

Here is a basic example of @babel/register in action:

From the command line:

$ node main.js
You will see this, because there is no syntax error!

main.js

require('@babel/register');
// This next file is compiled on the fly
require('./file1.js');

file1.js

import path from 'path';
console.log('You will see this, because there is no syntax error!');

The good thing is, this is how Mocha recommends you integrate Babel in their documentation. The --require option basically does what the above example does: require('@babel/register'); is called before Mocha uses require to import all of your test files.

Hope this helps! Again, this is a totally understandable mystery in the modern age of rapidly-evolving JavaScript.



来源:https://stackoverflow.com/questions/53874360/how-does-mocha-babel-transpile-my-test-code-on-the-fly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!