Jest won't transform the module - SyntaxError: Cannot use import statement outside a module

Jest won't transform the module - SyntaxError: Cannot use import statement outside a module

无论我怎样尝试,我都无法摆脱这个 SyntaxError: Cannot use import statement outside a module 错误,这让我很沮丧。这里有没有人解决了这个问题?我已经阅读了一百万个 Whosebug 和 github 个问题线程。没有明确的解决方案。

这是一个 React、Typescript、Webpack 项目。我正在尝试测试一个模块。但是 Jest 不会以某种方式将 模块转换为普通的 javascript

我得到的错误是

/Users/me/dev/Project/project/node_modules/variables/src/variables.js:12
    import './main.js';
    ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      17 | 
      18 | */
    > 19 | import { GlobalVars } from 'variables'
         | ^
      20 | 
      21 | export const Vars = new GlobalVars()
      22 | 

我试图解决这个问题(但没有奏效):

...等等。

我有这个设置:

package.json

  "jest": {
    "preset": "ts-jest",
    "testEnvironment": "node"
  }

.babelrc.js

module.exports = {
  presets: [
    ['@babel/preset-env', { targets: { node: 'current' } }],
    '@babel/preset-react',
    '@babel/preset-typescript',
  ],
  plugins: [
    '@babel/plugin-transform-runtime',
    '@babel/proposal-class-properties',
    '@babel/transform-regenerator',
    '@babel/plugin-transform-template-literals',
    'react-hot-loader/babel',
  ],
}

variables.ts

import { GlobalVars } from 'variables'

export const Vars = new GlobalVars()

variables.spec.ts

import { Vars } from './variables.ts'

describe('Test The Package', () => {
  it('Should accept new variables', () => {
    Vars.newVariable = 'new variable'
    expect(Vars.newVariable).toEqual('new variable')
  })
})

知道如何解决这个问题吗?

尽管我分别尝试过它们,但我没有一起尝试过它们(transformtransformIgnorePatterns)。所以这个玩笑配置解决了我的问题:

  "jest": {
    "preset": "ts-jest",
    "testEnvironment": "node",
    "transform": {
      "node_modules/variables/.+\.(j|t)sx?$": "ts-jest"
    },
    "transformIgnorePatterns": [
      "node_modules/(?!variables/.*)"
    ]
  },

我的错误是:

  1. 不一起使用 transformtransformIgnorePatterns
  2. 并将 babel-jest 定义为转换器而不是 ts-jest (我想当 jest 的 preset 定义为 [=17 时,这是一个问题=]。因为如果我将其更改为 babel-jest,它会再次抛出相同的错误。):
--- "node_modules/variables/.+\.(j|t)sx?$": "babel-jest"
+++ "node_modules/variables/.+\.(j|t)sx?$": "ts-jest"

由于 Jest 不能很好地与 esmodules 配合使用,您需要在 jest.config.js 中添加这些配置以告诉 Jest 使用 commonJS 构建来代替

moduleNameMapper: {
  '^variables$': 'variables/dist/cjs',
  '^[NAME OF MODULE YOU WANT TO IMPORT]$': '[NAME OF MODULE YOU WANT TO IMPORT]/dist/cjs'
}

另一种解决方法是使用 ts-jest, quoted from Jest's getting started

However, there are some caveats to using TypeScript with Babel. Because TypeScript support in Babel is purely transpilation, Jest will not type-check your tests as they are run. If you want that, you can use ts-jest instead, or just run the TypeScript compiler tsc separately (or as part of your build process).

我遇到了同样的情况。由于我有一个基于TypeScript的私有未编译包,并且我所有的源文件和测试文件都应用了ECMA(导入语法),所以我也遇到了以下错误。

SyntaxError: Cannot use import statement outside a module

我试过的解决方法

  • 上面的答案,比如在[=中使用transformtransformIgnorePatternsmoduleNameMapper 10=].
  • 关注JEST官方文档,Configuration Jest#transformignorepatterns-arraystring, I used exactly the same method and even referred to the use case from React Native Guide.
  • 删除了所有 node_modules,包括缓存,然后重新安装。
  • 使用 react-scripts 并将 jestbabel-jest 从 27 降级为 26 . 出现了另一个问题。

毕竟我是从JEST官方文档中找到ECMAScript Modules的,这四个步骤完美的解决了我的问题。我在这里粘贴了他们的说明,但是,您应该查看文档本身。

  1. 确保您通过传递 transform: {} 禁用代码转换或以其他方式配置您的转换器以发出 ESM 而不是默认的 CommonJS (CJS)。
  2. 使用 --experimental-vm-modules 执行节点,例如node --experimental-vm-modules node_modules/.bin/jest 或 NODE_OPTIONS=--experimental-vm-modules npx jest 等。在 Windows 上,你可以使用 cross -env 能够设置环境变量。
  3. 除此之外,我们尝试遵循节点激活“ESM 模式”的逻辑(例如查看 package.json 或 mjs 文件中的类型),详情请参阅他们的文档。
  4. 如果您想将其他文件扩展名(例如 ts)视为 ESM,请使用 extensionsToTreatAsEsm 选项。

您不一定需要将转换器从 babel-jest 更改为 ts-jest。

改为:

  1. 将您的 .babelrc 重命名为 babel.config.json https://babeljs.io/docs/en/configuration#whats-your-use-case

  2. 添加 transformIgnorePatterns:

    "transformIgnorePatterns": [
      "node_modules/(?!variables/.*)"
    ]

这解决了我的类似问题,无需添加额外的转换模式。 .babelrc 是您项目的本地项目,因此不会应用于 Jest 中的 node_modules

tl;dr: tsconfig.spec.json > { "compilerOptions": { "allowJs": true } }

这里提到的所有其他内容:

  • transformIgnorePatterns
  • 向转换部分添加一个附加模式
  • ...我后来恢复的更多

然后我调试进了transformer。首先我意识到:预配置的工作区不记录任何内容,甚至不记录到 ts-jest.log,不记录 --verbose--debug,甚至不记录警告,那本来是:

Got a .js file to compile while allowJs option is not set to true (file: {{path}}). To fix this:

  • if you want TypeScript to process JS files, set allowJs to true in your TypeScript config (usually tsconfig.json)
  • if you do not want TypeScript to process your .js files, in your Jest config change the transform key which value is ts-jest so that it does not match .js files anymore

(参见:ts-jest-transformer.ts

一个简单的解决方案是在 jest.config.js 文件中使用不同的预设。

不要使用默认 "preset": "ts-jest",而是尝试使用 "preset": "ts-jest/presets/js-with-ts" 等预设。基于documentation,它将:

ts-jest/presets/js-with-ts

TypeScript and JavaScript files (.ts, .tsx, .js, .jsx) will be transformed by ts-jest to CommonJS syntax. You'll need to set allowJs to true in your tsconfig.json file.

我的问题在某种程度上有所不同,jest 会偶然发现来自 node_modules 中依赖项之一的 .js 文件 SyntaxError: Cannot use import statement outside a module

我必须确保 ts-jest 不会忽略(在转换时)具有麻烦依赖性的 .js 文件。

仔细阅读 about presets 后,我意识到,它让他们 'as-is' 和 preset: 'ts-jest'。我将其更改为 preset: 'ts-jest/presets/js-with-ts' 并在 tsconfig.json.

中设置 "allowJs": true

为了不弄乱我的项目 tsconfig.json,我为 jest.

准备了一个单独的项目

最后,我的jest.config.js主要是这样的:

module.exports = {
    preset: 'ts-jest/presets/js-with-ts',
    testEnvironment: "node",
    globals: {
        'ts-jest': {
            tsconfig: '<rootDir>/test/tsconfig.json',
        },
    },
    transformIgnorePatterns: [
        "node_modules/(?!troublesome-dependency/.*)",
    ],
}

P.S。我不需要 transform 字段,因为预设已经在上面了。

P.P.S。我不需要介绍任何 babel 配置