尝试使用mocha、ES6模块和ts-node与--experimental-loader选项一起使用

3

我正在尝试让ts-node选项--experimental-loader与mocha一起工作,但没有成功。在开始尝试编译ES6模块之前,我曾经能够按照以下方式运行mocha测试:

"test": "nyc --reporter=html mocha --require ts-node/register src/**/*.spec.ts"

当生成ES6模块时,那种方法不再适用。

我会使用TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }'来进行测试,但由于另一个复杂性,这对我并不起作用:我首先生成ES6模块,然后使用webpack和babel生成ES5 / CommonJS模块。
除非在我的本地TypeScript的import语句末尾添加.js,否则最后一步将无法正常运行。

但是发现添加这些.js扩展名会破坏TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }'解决方案,如果我回去删除所有的.js扩展名,则此解决方案将起作用。显然,我不想在测试和构建过程中反复添加和删除这些扩展名。

为了简化,我已经移除了nyc,并尝试以以下方式运行测试:

mocha -r ts-node/register --experimental-loader ./ts-loader.mjs src/**/*.spec.ts

这种方式没有产生任何错误,但是也没有任何反应。就像 src/**/*.spec.ts 不存在一样。

我的无操作(暂时)虚拟加载器如下:

console.log('ts-loader loaded');

export async function resolve(specifier, context, defaultResolve) {
  console.log('resolve');
  return defaultResolve(specifier, context, defaultResolve);
}

export async function getFormat(url, context, defaultGetFormat) {
  console.log('getFormat');
  return defaultGetFormat(url, context, defaultGetFormat);
}

export async function getSource(url, context, defaultGetSource) {
  console.log('getSource');
  return defaultGetSource(url, context, defaultGetSource);
}

export async function transformSource(source, context, defaultTransformSource) {
  console.log('transformSource');
  return defaultTransformSource(source, context, defaultTransformSource);
}

export function getGlobalPreloadCode() {
  console.log('getGlobalPreloadCode');
  return '';
}

我可以看到加载成功的提示信息'ts-loader loaded',但是没有任何函数被调用。

我尝试了其他排列组合,但是仍然出现错误,例如将src/**/*.spec.ts视为字面文件名而不是glob,或者出现找不到模块的错误。

我希望能够看到每个import被处理时都调用我的loader,然后想办法操作文件扩展名,但是我还没有成功。有什么建议吗?

我正在使用node v14.15.1。可以在这里找到我的项目的完整代码,其中包括一个可工作的构建版本但测试不可用:https://github.com/kshetline/tubular_math

1个回答

1

我终于找到了一个解决方案,尽管它与我最初寻找的方向不同。我放弃了试图让mocha接受额外的.js扩展名,并找到了一种方法可以使webpack在没有这些扩展名的情况下正常工作。所以...

import { Angle, Mode, Unit } from './angle.js';

...回到了...

import { Angle, Mode, Unit } from './angle';

我的测试脚本长这样:

  "scripts": {
    "build": "rimraf dist/ && tsc && webpack && webpack --env target=umd",
    "prepublishOnly": "npm run build",
    "lint": "eslint 'src/**/*.ts'",
    "test": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter=html mocha --require ts-node/register src/**/*.spec.ts"
  },

最后,最重要的是,我解决了如何使webpack 5.x(4.x没有这个问题)满足本地JavaScript导入而不需要.js扩展名的问题。如果你的package.json中写着"type": "module",则webpack现在将要求.js扩展名。

    module: {
      rules: [
        { test: /\.js$/, use: 'babel-loader', resolve: { fullySpecified: false } }
      ]
    }

...其中将fullySpecified设置为false是解决方案的关键。

更新:上面的示例是在一个故意简单的项目上完成的,这对于初学者来说很容易生成一个带有ESM模块的npm包。现在我正在尝试一些更高级的东西,我又遇到了一个问题,就是运行单元测试时遇到了问题。只要*.spec.ts文件直接或间接地导入外部代码,模块加载就会失败。在我找出如何解决这个问题之前,我只能测试没有外部依赖的代码。显然,使用"TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}'只能让我深入到修复运行mocha和ts-node的基本问题的一个层次。


我遇到了与单元测试完全相同的问题。通过 import * as umd from "umd"; Webpack愉快地引入了UMD,但是Mocha却在相同的代码中出错了。 我不知道怎么回事就随机解决了它,但是后来重建后,一切又都失败了。你解决了这个问题吗? - user3337629
很遗憾,事实上我最近想在一个 TypeScript 项目中使用一个仅支持 ESM 的 npm 包(double-metaphone)。由于各种模块格式问题让我感到非常沮丧,我放弃了导入该包,并将其源代码(幸运的是很小)直接复制到我的项目中。 - kshetline
最终我还是做了我本来想要避免的事情:通过webpack将我的规范与源代码捆绑在一起,并通过Karma在浏览器中运行测试。这似乎是一个非常沉重的包,只是为了能够运行一些没有与其他模块集成的测试。然而,在mocha中导入非es6模块时,模块解析就无法正常工作。 - user3337629

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接