Jest ESM 和 ts-jest - 当某些依赖项是 CJS 而某些依赖项是 ESM 时如何处理

ner*_*ger 8 apollo reactjs jestjs apollo-client ts-jest

使用 Jest(ESM 和 ts-jest)导入 CJS 模块时遇到一些问题。最小复制回购

例如,按照其文档@apollo/client中所述从模块导入:

import {
  ApolloClient,
  InMemoryCache,
  ApolloProvider,
  useQuery,
  gql
} from '@apollo/client';
Run Code Online (Sandbox Code Playgroud)

每个导入都会给出类似的错误SyntaxError: The requested module '@apollo/client' does not provide an export named 'ApolloProvider'。查看 的@apollo/clientpackage.json ,"main"key设置为"./main.cjs",这是用cjs风格重新导出东西:

var core = require('./core');
var react = require('./react');

for (var k in core) {
    if (k !== 'default' && !exports.hasOwnProperty(k)) exports[k] = core[k];
}
for (var k in react) {
    if (k !== 'default' && !exports.hasOwnProperty(k)) exports[k] = react[k];
}
Run Code Online (Sandbox Code Playgroud)

由于某种原因,我猜想推荐的 jest 配置无法识别此 cjs。要解决这个问题,可以直接从@apollo/client包中的 esm 文件直接导入特定的导出,如下所示:

import {
  ApolloClient,
  InMemoryCache,
} from '@apollo/client/core';
import { ApolloProvider } from '@apollo/client/react/context/ApolloProvider';
import { useQuery } from '@apollo/client/react/hooks';
import { gql } from 'graphql-tag';
Run Code Online (Sandbox Code Playgroud)

然后有一个新的依赖错误:

/path/to/project/node_modules/ts-invariant/process/index.js:15
    export function install() {
    ^^^^^^

    SyntaxError: Unexpected token 'export'
Run Code Online (Sandbox Code Playgroud)

添加transformIgnorePatterns到 jest 配置似乎没有帮助:

    "transformIgnorePatterns": [
      "node_modules/(?!(ts-invariant)/)"
    ],
Run Code Online (Sandbox Code Playgroud)

关于如何修复有什么想法吗?

完整的笑话配置:

  "jest": {
    "resetMocks": true,
    "testEnvironment": "node",
    "testMatch": [
      "**/src/**/*.(spec|test).[tj]s?(x)"
    ],
    "preset": "ts-jest/presets/default-esm",
    "transform": {},
    "transformIgnorePatterns": [
      "node_modules/(?!(ts-invariant)/)"
    ],
    "extensionsToTreatAsEsm": [
      ".ts",
      ".tsx"
    ],
    "globals": {
      "ts-jest": {
        "useESM": true
      }
    },
    "moduleNameMapper": {
      "^(\\.{1,2}/.*)\\.js$": "$1"
    }
  }
Run Code Online (Sandbox Code Playgroud)

和 tsconfig:

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "declaration": true,
    "downlevelIteration": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "jsx": "react",
    "outDir": "build",
    "sourceMap": true,
    "strictNullChecks": true,
    "baseUrl": ".",
    "lib": [
      "ESNext",
      "dom"
    ],
    "moduleResolution": "Node",
    "target": "ESNext",
    "module": "ESNext"
  },
  "include": [
    "src/**/*"
  ]
}
Run Code Online (Sandbox Code Playgroud)