mocha / babel 如何动态转译我的测试代码?

Fra*_*cke 7 mocha.js node.js transpiler ecmascript-6

我的问题不是为什么有些东西不起作用,而是为什么它起作用。是的。

\n\n

我有一个小型的nodeJS命令行工具,其中包含nodeJS尚不支持开箱即用的功能,最值得注意的是:

\n\n
    \n
  • import声明
  • \n
  • String.includes()
  • \n
\n\n

因此,对于交付(构建),我转译+捆绑我的源代码(使用parcel,就像webpack一样)。

\n\n

令人惊奇的是,我的所有(除了一个)摩卡测试都直接针对我的类而不是捆绑包运行。尽管如此,它们仍然有效!包括很多import说法。并包括“ES6 自测试”:

\n\n
it( \'String - include\', () => {\n    var s = \'Southern Bananas\'\n    assert( s.includes( \'anana\' ) )\n    assert( !s.includes( \'kiwi\' ) )\n} )\n
Run Code Online (Sandbox Code Playgroud)\n\n

因此:

\n\n

我的测试代码中有 String.include ,而不仅仅是在被测试的源代码中。并且没有地方可以转译或捆绑我的测试代码\xe2\x80\xa6 因此,对我的愚蠢问题表示歉意:

\n\n

为什么这有效?某处是否有秘密的即时编译?(如果是的话,我也可以将其用于我的可交付测试代码的调试风格吗?)

\n\n

我的mocha.opts比较简单:

\n\n
--require @babel/register\n--require ./test/once.js  (nothing special here, either)\n--reporter list\n--recursive\n
Run Code Online (Sandbox Code Playgroud)\n\n

我的.babelrc有这个:

\n\n
{\n    "presets": [\n        [\n            "@babel/preset-env",\n            {\n                "targets": {\n                    "Electron": "3.0",\n                    "Node": "8.0"\n                }\n            }\n        ]\n    ],\n    "plugins": [\n        "@babel/plugin-transform-runtime"\n    ],\n    "retainLines": true,\n    "comments": false,\n    "sourceMaps": true\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

@babel/plugin-transform-runtime显然不是责怪赞美,因为它明确指出

\n\n
\n

注意:诸如 "foobar".includes("foo") \n 之类的实例方法将不起作用,因为这需要修改 \n 现有的内置函数(您可以使用 @babel/polyfill 来实现)。

\n
\n\n

@babel/polyfill包含在简约现代的afaik中吗@babel/preset-env?我还做对了什么:+)?有没有办法将这个实时编译也用于我的(调试)构建?

\n

Mat*_*ahl 6

长话短说

String.prototype.includesNode.js 自 v6.5 起支持。@babel/register导致您的代码被动态编译,这就是您的import语句起作用的原因。我怀疑你需要这个@babel/plugin-transform-runtime插件,除非我错过了你想要实现的目标。

什么会导致这种混乱?

我认为这个(完全可以理解的)谜团有两个根本原因:

  1. Babel 作者使该工具的使用变得非常容易;有时很难知道如何/何时调用它(特别是与 Mocha 等其他工具配合使用时)。
  2. Node.js 原生支持/不支持的内容(就 ES2015、ES2016 等而言)传统上很难跟上。

那么,接下来就是两个谜团了。

为什么String.prototype.includes有效?

这个有更简单的解释。String.prototype.includes早在 Node.js v6.5 就已经得到原生支持(如您所见,从该版本开始就支持绝大多数 ES2015)。

因此,虽然您没有@babel/polyfill配置(据我所知)并且您在不支持的环境中需要它String.prototype.includes您的环境已经支持它了

来自 Node.js v8.x REPL:

> 'ES2015'.includes('2015')
true
Run Code Online (Sandbox Code Playgroud)

为什么你的import声明有效?

正如您所说,Node.js v8.x本身并不支持 ECMAScript Modules。然而,有一些关于如何从 Node.js v9.x 开始启用它作为实验性功能的好文章。

因此,您可以使用本机 Node.js v8.x(通过 REPL)获得以下内容:

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

SyntaxError: Unexpected token import
Run Code Online (Sandbox Code Playgroud)

您的导入起作用的原因是 Babel 使用@babel/preset-env预设来编译您的代码。此外,该编译是由您的 Mocha 选项触发的--require @babel/register

@babel/register其工作原理是“将自身绑定到节点的要求并自动动态编译文件”。

这是@babel/register实际操作的一个基本示例:

从命令行:

$ node main.js
You will see this, because there is no syntax error!
Run Code Online (Sandbox Code Playgroud)

main.js

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

文件1.js

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

好消息是,这就是 Mocha 建议您在其文档中集成 Babel 的方式。该--require选项基本上执行上面示例的操作:在 Mocha 用于导入所有测试文件require('@babel/register');之前调用。require

希望这可以帮助!同样,在 JavaScript 快速发展的现代时代,这是一个完全可以理解的谜团。

  • 据我所知,`@babel/register` 确实在内存中编译。但它确实维护一个[默认缓存](https://babeljs.io/docs/en/babel-register#babel-cache-path)。[缓存在启动时加载到内存中](https://github.com/babel/babel/blob/master/packages/babel-register/src/node.js#L119)。Babel 的仅供开发使用的 CLI 是 [`@babel/node`](https://babeljs.io/docs/en/babel-node)。它的行为与 Node CLI 相同,只是它在执行之前编译文件。也许你可以用那个?或者将 `@babel/register` 集成到 CLI 的入口点中。 (2认同)