您要请求功能还是报告错误?
我想申请一个功能。
目前的行为是什么?
现在 Jest 不支持带有import
语句的测试套件。 它们导致以下错误:
SyntaxError: Unexpected token import
at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:305:17)
at Generator.next (<anonymous>)
at new Promise (<anonymous>)
什么是预期行为?
如果 Jest 原生支持 ES 模块,那就太好了。
请提供您确切的 Jest 配置并提及您的 Jest、节点、yarn/npm 版本和操作系统。
笑话: 21.2.1
节点: 8.9.0
npm: 5.5.1
之前,ES 模块的原生支持是不可能的,因为 node.js 不支持它们。 从几个版本之前开始,node.js 添加了对带有标志的 ES 模块的支持(https://nodejs.org/api/esm.html)。 如果 Jest 也将其与添加对 ES 模块的支持相匹配,可能带有标志或什至没有标志,那绝对是很棒的。
Node.js 要求 ES 模块具有.mjs
扩展名。 为了支持 ES 模块,Jest 需要添加对这些扩展的识别。 Jest 还需要将--experimental-modules
标志传递给 node.js,直到 node 实现对没有标志的模块的支持。 我不确定在 Jest 中是否需要任何其他必需的更改来支持这一点。 我只能希望这不会太难。
理想情况下,即使 Jest 也能识别没有.mjs
扩展名的文件中的模块会很酷,因为针对浏览器的代码不使用它们,但我不知道这是否可能。 Node.js 为此提供了加载器钩子 (https://nodejs.org/api/esm.html),但这仍然不能通过可靠地确定文件是什么类型的模块来解决问题。
我相信 ES 模块是一个很棒的特性,远远优于所有现有的 JS 模块解决方案。 在 node.js 中实现它为 Jest 也打开了一扇门。 这将使开发人员不仅在整个开发过程中坚持使用第一个真正标准化的 JS 模块格式,而且还通过测试。
Jest 有自己的require
实现(https://github.com/facebook/jest/blob/master/packages/jest-runtime/src/index.js),所以它会比仅仅涉及更多支持语法并默认查看.mjs
。 我也反对激活实验标志。
自动转译import
/ export
是可能的,但是实现语义是一项艰巨的任务,并且由于支持节点 6 可能会被阻止一年。
我同意 SimenB。 我们需要来自节点团队的许多钩子才能与 vm 模块一起工作。 但是,我认为我们应该同时支持这一点,但不是通过镜像完整的本机实现,而是通过使用 babel 并将其编译为 require 内部babel-jest
。 我认为出于测试目的,这将正常工作,我们不必提供节点运行时需要提供的相同保证。
所以只需将babel-plugin-transform-es2015-modules-commonjs
和babel-plugin-dynamic-import-node
到babel-jest
?
是的,我就是这么想的。
伙计们,集成https://github.com/standard-things/esm怎么样? 它速度很快并且维护了很多边缘情况。
@TrySound具体会是什么样子? 你能做一个原型吗?
我们仍然有自己的需求实现(需要模拟),所以我认为这没有多大帮助。
我们需要同时处理 Node 的规则和浏览器的规则。
我很高兴得到纠正并让它对我们完美地工作:D
@std/esm
显然应该只是开玩笑: https :
任何人都可以试一试并返回文档的 PR 吗? 🙂
我猜用户希望到处都有支持,但我发现它仅适用于测试文件的依赖项。
// test.js
require = require('@std/esm')(module, { esm: 'js', cjs: true });
const utils = require('./utils');
// utils.js
export { default as update } from './update';
它更好,但并不理想。
那么只需将 babel-plugin-transform-es2015-modules-commonjs & babel-plugin-dynamic-import-node 添加到 babel-jest 中?
我不认为这是一个很好的解决方案,因为它不会执行任何对 ES 模块非常有价值的“丢失导出”检查。 例如,在 React repo 中,我开始更频繁地运行 build 只是因为 Rollup 发现了这些错误,但 Jest with es2015-modules-commonjs
没有。
@std/esm 显然应该只用玩笑
将一些时间投入到他们的互操作中会非常棒。 很确定这个 hacky 解决方案最终会崩溃: https :
@SimenB ,在我看来,直接的步骤不会太复杂。 紧迫的是允许人们使用 .mjs 模块,即使 babel 正在帮助测试场景。 否则,如果人们想使用 .mjs,他们可能不得不寻找不同的测试解决方案。
最终的解决方案可能很复杂并且需要时间,但这是不可避免的,不是吗?
你好,有人能修复这个错误吗?
我们正在使用带有“node --experimental-modules”选项的 .mjs。 任何解决方法?
我们正在使用带有“node --experimental-modules”选项的 .mjs。 任何解决方法?
这是实验性的,并没有完全充实。 基本的东西仍然有很多流失,比如如何导入内置模块,仍然悬而未决。 像 AVA 这样的项目已经开始允许使用@std/esm
作为他们的加载器管道(如果使用的话)(绕过 Babel)。 也许 jest 可以采取类似的方法。
支持@std/esm
是我们想做的事情,非常欢迎帮助实现它!
@SimenB你能在环聊的某个时候聊天吗?
这很酷! 感谢分享。
我们必须弄清楚我们希望集成在哪里。 它如何处理 CSS(或其他非 js 资产)文件? 它应该只是一个转换吗? 内置的 babel 转换怎么样? 如果 Jest 确实会影响任何东西,那么在传入加载器时应该如何表现?
似乎对社区贡献esm
启用的备用玩笑跑步者(或非官方/实验性标志)可能有好处,因此我们可以在类似的事情上取得进展。 Jest 团队会对此感兴趣吗?
require
没有在 runner 中实现,它在运行时本身中。 任何使其可插拔的贡献都非常受欢迎(参考#848)。
我敢肯定,如果您可以将示例代码@jdalton链接到工作而没有问题(或接近它),它应该足够简单,可以在开玩笑本身的标志后面加载 esm 加载器。 我认为有问题的一件事是它想要真正的module
全局,而不是我们创建的假的。 不确定这是否意味着模块会在测试之间泄漏? 我不知道 esm 在幕后做了什么。 它也不处理模拟,所以用import
模拟仍然会中断
可能只需要对 Jest 如何进入 CJS 进行一些调整。 例如,当模拟module
对象时,它可以使用require("module")
代替普通对象,然后包装/覆盖module.require
以拦截请求并根据需要进行处理。
更新:
我现在正致力于使用esm
开箱即用地启用 Jest (希望 Jest 不必做任何不同的事情) 。 我将在周末继续试验,但早期迹象看起来不错。
@jdalton任何与esm
兼容的更新?
嗨@JasonCust ,哇,我的评论引起了一些注意!
我在确定在esm
启用 Jest 支持所需的工作方面取得了进展。 在我的实验中,我使用 ESM 编写了 Jest 加载和评估测试。 esm
加载器端所需的工作是使我们处理vm.Script
使用更通用。 目前我们主要是为了 REPL 使用它,它假设一个模块。 我们必须让 Jest 支持更通用一些。 看起来 Jest 不需要改变任何东西。 我们的vm.Script
支持的重构仍然在我的 TODO 上,并且在我发布实验性 WASM 支持之类的东西之前仍然会得到解决。 目前,我一直在解决围绕改进的 APM 和模拟支持出现的错误。
感谢@jdalton的更新,因为我很高兴能够在 Jest 中使用esm
。 为了在您处理这些事情时不打扰您,是否有esm
的任务可以让我们跟随进度?
您可以继续订阅此线程以关注 repo。 Jest 支持将在 v3.1.0 版本中提供,因此您可以留意该版本。
@jdalton 有关于在
嗨@deepj!
它仍然在我的清单上,在完成这项工作之前我可以处理的项目正在减少。 我一直在改进 Jest 中测试esm
模块的补充 Jest 支持 _(虽然 CJS 在 Jest 测试中)_。 在 Jest 方面仍然没有任何严重阻碍实现_(所以他们没有工作要做)_。 我的雇主 Microsoft 也是 Jest 的重度用户,因此改善这一点也是我的日常工作目标之一。 我希望尽快解决它。
@jdalton很
真的很期待这个功能:speak_no_evil:
过去两个小时一直在尝试使此功能正常工作。 有这么多部分解决方案,半文档化的答案,彼此都不同......过去很容易测试node.js包。
所以只需将
babel-plugin-transform-es2015-modules-commonjs
和babel-plugin-dynamic-import-node
到babel-jest
?
这个想法是怎么回事? 实施时有什么问题吗?
嗨@jdalton。 我想知道您是否可以让我们了解此问题的最新状态。 对不起,如果我打扰你,但我等了一段时间,如果我们至少能在过去/未来六个月收到更新会更好。 谢谢 :)
嗨@SurenAt93!
感谢您的耐心等待。 我希望能在本月底在 Jest 的支持下发布一个版本。 有了它,您将指定esm
作为 Jest变换。
凉爽的。 这种转换与 Babel 有何不同?
@kenotron
使用 Jest 的transform
选项是我侧载esm
加载器的一种方式。 因此,虽然它在技术上也在转换源代码,但它也在连接esm
加载器。
如果问题更多,Babel 和esm
之间有什么区别。 Babel 是转换源的包的集合,其中一个目标可能是 ESM 语法。 esm
加载器是一个模拟运行时环境的零依赖加载器。 所以esm
支持动态import()
,通过相关的test262规范(时间死区、实时绑定、前期错误等),并支持将 CJS/ESM/WASM 的混合加载到按配置品味。
@jdalton感谢您的工作和支持!
@tomheller ;)
过去两个小时一直在尝试使此功能正常工作。 有这么多部分解决方案,半文档化的答案,彼此都不同......过去很容易测试node.js包。
我同意。
我创建了一个简单的Vue项目,也体现了这个问题。
https://github.com/igasparetto/vue-jest-test
我无法让它工作。
我按照以下页面的说明进行操作:
我的机器(不确定它是否重要):
@kenotron
使用 Jest 的
transform
选项是我侧载esm
加载器的一种方式。 因此,虽然它在技术上也在转换源代码,但它也在连接esm
加载器。如果问题更多,Babel 和
esm
之间有什么区别。 Babel 是转换源的包的集合,其中一个目标可能是 ESM 语法。esm
加载器是一个模拟运行时环境的零依赖加载器。 所以esm
支持动态import()
,通过相关的test262规范(时间死区、实时绑定、前期错误等),并支持将 CJS/ESM/WASM 的混合加载到按配置品味。
@kenotron你能给我们提供更新吗?
@igasparetto , @jdalton的工作应该能够实现这一点。 我还没有尝试过那个解决方案。
我认为那里的最新状态是: https :
是的! 抱歉,它花费的时间比我想要的要长。 在本地,我现在已经通过了所有相关的 test262 测试。 在获取这些内容的过程中,与模拟相关的场景测试失败了,因此我必须在发布之前将它们重新拾起。 这不是不可逾越的,只是需要一点时间。 我将于 1 月 16 日在Covalence Conf上发表演讲,希望届时能发布。 在其他新闻中, npm tink
早期采用了esm
作为其 ESM 语法支持🤝。
1 月 16 日,希望届时能发布
@jdalton我希望演讲进展顺利。
请问你有这个版本的更新吗?
@igasparetto在https://github.com/standard-things/esm/issues/97#issuecomment -454985896 和https://github.com/standard-things/esm/issues/706 ☺️
我在这里留下一个小的“数据点”来帮助您进行规划。 我意识到你们都在贡献自己的时间和技能来解决这个问题。 作为开发人员,我感谢您的贡献。
我昨天花了大部分时间,至少一个星期六,来加快客户端和服务器端的 javascript 模块的速度。 ESM、CommonJS、AMD,真是一团乱麻。 我从来没有得到一个笑话测试来使用 ESM 加载一个使用 .mjs 扩展名的(节点)模块。 我可以在客户端成功加载相同的模块。 我可以创建一个节点“客户端”,该节点使用带有导入语句的模块。 我无法正确配置 jest 以使用相同的 import 语句,无论有没有 babel,有或没有 esm。 我最终切换到 ava,并按照他们网站上的食谱让它工作。 是的,我遵循了一个食谱,我不完全了解使所有零件正常工作的机器。 但至少我现在可以编写 ESM 加载 javascript 模块和相关的单元测试。 我认为。 我是在一次成功的基础上进行推断的。 他们还有一个将 ava 连接到 webstorm 的方法。 但至少他们正在向像我这样的凡人展示食谱。
我也意识到这条消息会读起来就像我在抱怨(部分是我)。 我看到所有的工作都变成了玩笑。 但是这个 ESM 支持对我来说是一个杀手和一个交易破坏者。 以为您会欣赏一些反馈,但如果没有,请忽略此内容或要求我将其删除,我会的。
@dandv我一直在调查 Jest 是否可以支持节点 12 中的原生 ES 模块。这将涉及 Jest 使用vm.SourceTextModule
API,这需要将一些 CLI 标志传递给node
:
--experimental-modules --es-module-specifier-resolution=node --experimental-vm-modules
API 也是超低级的。
待定。
更新:被告知要等到 Node 的模块加载器的设计被锁定。 同时,standard-things/esm#706 可能是最好的选择。
jest 是一个非常好的测试库。 支持esm真的一切都需要完成!
更新:被告知要等到 Node 的模块加载器的设计被锁定。 同时, standard-things/esm#706可能是最好的选择。
可悲的是,这不适用于开玩笑。
@jdalton我们正在使用lodash-es ,它是lodash-es可以通过 Webpack v4 进行摇树! ( ◔ ౪◔)⊃━☆゚.*・.
不幸的是,鉴于 Jest 尚不支持 ES 模块,这给我们带来了问题。 我们希望这个功能很快就会成为 Jest 的一部分。 有人会碰巧知道如何让lodash-es与 Jest 一起工作吗?
node_modules\lodash-es\lodash.js:10
export { default as add } from './add.js';
^^^^^^
SyntaxError: Unexpected token export
我们也在使用jest-preset-angular npm 包。
module.exports = {
testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
transform: {
'^.+\\.(ts|js|html)$': 'ts-jest'
},
resolver: '@nrwl/builders/plugins/jest/resolver',
moduleFileExtensions: ['ts', 'js', 'html'],
collectCoverage: true,
coverageReporters: ['html']
};
不幸的是,鉴于 Jest 尚不支持 ES 模块,这给我们带来了问题。 我们希望这个功能很快就会成为 Jest 的一部分。 有人会碰巧知道如何让lodash-es与 Jest 一起工作吗?
告诉 Jest 在转换时不要忽略 lodash-es:
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\](?!lodash-es/).+\\.js$"
],
@azz你知道 Node 的模块加载器的设计什么时候会被锁定吗?
因为:
npx -n '--experimental-modules' jest func.spec.js
会非常酷和轻松的生活。
自从 Node.js v12.0.0 于 2019 年 4 月 23 日发布后,一切又发生了变化
当事情被 babel 破坏时,我写了 npm 包jest-esnext
它似乎适用于 Node.js 12+ 不变,即。 package.json 和扩展名 .js 中的“类型:模块”
jest-esnext 中的策略是在依赖项中进行所有转译,从而实现稳定的 babel 环境。 消费项目不需要babel
https://www.npmjs.com/package/jest-esnext
https://github.com/haraldrudell/ECMAScript2049/tree/master/packages/jest-esnext
@haraldrudell根据说明不清楚如何使用该包,它说:在 package.json 旁边创建名为 jest.config.js content module.exports = require('jest-esnext')
,但是如果我已经有了配置怎么办? 如何整合?
这是使用的文件
您可以将_default
的内容替换为jest.config.js
嗨,大家好,
node 12.13.0 LTS 终于发布了……有关于这件事的消息吗?
@mtsmachado8恐怕 v8 团队仍然需要一些时间来解决这个问题,因为我看到 ESM 模块仍然被标记为实验性......他们可能在路线图上失败了。
对于未标记的 ESM,此 PR 已到位
https://github.com/nodejs/node/pull/29866
@azder @haraldrudell所以基本上在您的解决方案中,您对所有 JS 文件(包括node_modules
文件)进行 Babel 转换?
就我而言,我不得不直接使用您的预设,因为我还没有找到如何像这样配置变压器:
const babelPreset7Esnext = require('babel-preset-7-esnext');
const babelJest = require('babel-jest');
module.exports = babelJest.createTransformer(
babelPreset7Esnext(undefined, {decorators: {legacy: true}})
);
节点现在默认切换模块支持
ECMAScript 模块默认支持登陆 13.2.0
https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V13.md#13.2.0
在加载器可用之前,我们不会对此进行处理。 没有它们,Node 就没有 Jest 提供适当支持所需的钩子。 请参阅https://medium.com/@nodejs/annoucing -core-node-js-support-for-ecmascript-modules-c5d6dc29b663(我无法直接链接到该部分,但它是“正在进行的工作”部分在底部)
对于那些使用本机模块并想要使用jest 的人。
在您处理此问题时,我建议对 node v. 13.2.0 进行快速修复:
babel-plugin-transform-default-import
用法(在 _package.json_ 中):
{
"babel": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
],
"plugins": ["transform-default-import"]
},
}
libs需要安装:
npm i --save-dev @babel/core @babel/preset-env babel-plugin-transform-default-import
注意:如果你没有名为 export 的 babel 库(或者你不使用它),你可能不需要使用 babel-plugin-transform-default-import
@infodusha很棒:)。 这次真是万分感谢。
在我的项目中,它无需插件即可工作:
npm i --save-dev @babel/preset-env
babel.config.js
(必须如此命名,而不是.babelrc
):
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
node: '13.2',
},
modules: 'commonjs',
},
],
],
plugins: [],
};
诀窍是将文件分成目录并在其中使用适当的package.json
:
在test
目录中,我使用了
{
"type": "commonjs"
}
而在src
目录中:
{
"type": "module"
}
@azder但是,如果您导入在本机模块中提供 commonjs 命名导入的包,则需要使用默认导入来导入它,而在 babel 中,您需要使用命名导入。 可能你没有这样的包,或者没有提供 es6 导出的包,但并不是所有的包都准备好明天做
@infodusha可能我现在没有什么? 您是否尝试过我写的内容并发现它有问题,还是只是假设我在使用它时遇到了问题?
请提供一个实际示例,因为我不清楚您所说的“在本机模块中提供名为 import 的 commonjs 的导入包”是什么意思。
到目前为止,我在编写所有带有.js
文件扩展名的文件时没有遇到任何问题,其中./src
目录是"type":"module"
和./test
目录"type":"commonjs"
与此:
const imported = require('../src/module.js').default;
const {anotherOne} = require('../src/module.js');
那是因为Jest默默地将ES 模块转换为CommonJS代码。
这是我认为应该在本地测试ES 模块的内容:
(async () => {
const [
{ default: imported },
{ anotherOne },
] = await Promise.all([
import('../src/some-module.js'),
import('../src/another-module.js'),
]);
// Rest of your test goes here.
})();
@azder这些是解决方法。
使用 package.son type=module
和其中的两个文件创建一个目录mymodule
: first.js
和second.js
。
然后尝试import { first } from "mymodule";
您需要在 json 中设置exports
字段才能使用 Node ESM,并且现在没有任何包具有它(即:lodash)。
您的示例可能似乎有效,但是只要some-module.js
或another-module.js
尝试import
命名模块,它就会中断:它们将在级联上中断。
@damianobarbati您_ _必要性"type": "module"
的package.json
,没有它,一切.js
您的模块文件被加载,为CommonJS的。
exports
仅用于限制暴露给外部消费者的内容,对于条件导出,它对.js
文件是否会被解析为CommonJS或ESM完全没有影响。
@damianobarbati你错了,正如@Exe-Boss 所说,顺便说一句,
这是因为 Jest 默默地将 ES 模块转换为 CommonJS 代码。
是的,我依赖 Jest 怪癖,这就是我使用babel.config.js
,甚至没有在devDependencies
添加 babel
@damianobarbati
请注意,我有一个工作项目,其中我使用 Jest 转译,而 src 目录具有模块类型,注意, ./src
不是 babel 配置文件所在的根目录(那个是 CJS由于怪癖)。
此外,您是对的,因为我没有从 NPM 中导入任何 CJS 的内容,因为我认为 NPM(或包作者)还没有准备好进行混合搭配。
我的项目的目标是只有 ESM(减少工具脂肪),所以 Jest 是唯一可以自行编译的例外。
@damianobarbati
类似的东西,这里是项目https://github.com/azder/clip 。 请注意,根据博客文章摘录的最后一句,我的package.json
没有“依赖项”,我决定不混合来自 NPM 的 ESM 和 CJS 模块。
这种方式为了满足 Jest 的需求,它确实转换了我的 ESM 模块的要求,但可能需要更多的 babel 配置来处理node_modules
目录。
https://medium.com/@nodejs/annoucing -a-new-experimental-modules-1be8d2d6c2ff
目前,无法创建可通过 require('pkg') 和 import 'pkg' 使用的包。 正在努力解决这个问题,并且可能涉及对上述内容的更改。 特别是,Node.js 可能会选择“main”以外的字段来定义包的 ES 模块入口点。 虽然我们知道社区已经接受了“模块”领域,但 Node.js 不太可能采用该领域,因为许多使用“模块”发布的包包括 ES 模块 JavaScript,它们可能无法在 Node.js 中评估(因为扩展名不包含在文件名中,或者代码包含 require 语句等)。 在解决此问题之前,请不要发布任何供 Node.js 使用的 ES 模块包。
请参阅我刚刚打开的 #9430 以跟踪 Jest 中的支持。 我会保持这个问题开放讨论。
@SimenB这是一个好兆头! 这一点以及在 Jest 25 发行说明中提到的模块让人希望早日看到支持。
@SimenB如果我没记错的话,Jest 无法使用仅作为 ESM 发布的 NPM 包,这也被迫为某些node_modules
包启用 Babel。 这有改变吗?
您需要转换导入/导出,直到支持登陆,用户和库代码
@西蒙B :
您需要转换导入/导出,直到支持登陆,用户和库代码
对于我们的情况,到目前为止最好的方法是这样,因为我们所有的包都有/es/
目录,但这很脆弱,可能不适合其他项目:
transformIgnorePatterns: ['node_modules/(?!.*?/es/.*\\.js)'],
就像你说的那样,尽管type: module
,Jest 并没有选择那些没有转换的包。
您需要转换导入/导出,直到支持登陆,用户和库代码
有没有粗略的时间表?
从节点 14 版本开始:
我们相信当前的实现为编写 ESM 模块提供了一个面向未来的模型,为通用 JavaScript 铺平了道路。 请在我们的文档中阅读更多内容。
Node.js 中的 ESM 实现仍处于试验阶段,但我们相信我们已经非常接近能够在 Node.js 中“稳定”调用 ESM。 消除警告是朝着这个方向迈出的一大步。
因此,我不愿意使用 commonJS 更长时间地导出 NPM 包(这些包很可能被实现 JEST 测试框架的测试所消耗)。
我们正在发布 Jest 25.4 的实验版本。 在 25.5 中修复了相当多的错误,但它仍然不是它应该的地方。 可以关注#9430的进度
最有用的评论
可能只需要对 Jest 如何进入 CJS 进行一些调整。 例如,当模拟
module
对象时,它可以使用require("module")
代替普通对象,然后包装/覆盖module.require
以拦截请求并根据需要进行处理。更新:
我现在正致力于使用
esm
开箱即用地启用 Jest (希望 Jest 不必做任何不同的事情) 。 我将在周末继续试验,但早期迹象看起来不错。