无法在模块外使用导入语句 - 使用 Axios

89

我有一个 Vue.js 应用程序,其中两个文件包含以下内容:

import axios from "axios"

这些文件位于应用程序中的 src/lib 目录中,并在其第一行包括了该导入语句。

在 Github 上运行测试导致安装 Axios 1.0.0,无论 package.json 中写的是什么,现在任何涉及这些文件的测试都会失败并出现上述错误。

将该语句更改为 const axios = require("axios") 也会失败;node_modules/axios/index.js 在第一行包含一个导入语句,并在那里抛出异常。

针对这种问题,我经常看到的建议是在 package.json 中添加 "type": "module" (与 src/ 处于同一级别)。这会导致所有测试都以要求将 vue.config.js 重命名为 vue.config.cjs 的方式失败。这样做会让我得到: Error: You appear to be using a native ECMAScript module configuration file, which is only supported when running Babel asynchronously ,但我不理解这是什么意思。

有人能建议在这里该怎么做吗?


如果这个问题附带有代码,那么它会很有帮助。 - Rajashekhar Reddy
你期望我附上哪段代码? - knirirr
就像你尝试导入的地方,以及你如何尝试导入。 - Rajashekhar Reddy
谢谢。上面的问题已经说明了“如何”。至于“在哪里”,我不确定这在这种情况下会有什么帮助。但我还是会加进去的。 - knirirr
15个回答

225

通过强制 jest 导入 commonjs 版本的 axios 构建,我成功解决了这个错误。

  "jest": {
    "moduleNameMapper": {
      "axios": "axios/dist/node/axios.cjs"
    }
  },

针对我的package.json, 其他使用transformIgnorePatterns的解决方案对我不起作用。


50
有人请这位先生喝一杯啤酒,这是唯一能解决我的问题的方法。在StackOverflow上广为流传的“transformIgnorePatterns”解决方案对我无效,我花了几个小时都没能解决问题。这是唯一有效的方法。感谢@rcbevans。 - Cheyne
4
谢谢,这个方法对我也有用,但是我必须将它添加到我的jest.config.js文件中。 - spetry
9
如果您使用react-scripts,只有在更改package.json时才能起作用。我曾在jest.config.js中尝试过,但它没有任何效果。 - user926643
4
成功了!dist路径可能因版本而异。对于我的版本,它是 axios/dist/axios.js,我不得不加一个window全局变量。但似乎已经成功了! - isick
2
请注意,moduleNameMapper的键是基于正则表达式匹配的,因此此答案将影响包含“axios”的任何文件路径,即使它们位于axios模块之外。您可以使用"moduleNameMapper": { "^axios$": "axios/dist/node/axios.cjs" }来缩小范围- 这样更安全,避免了意外重新映射。 - mamacdon
显示剩余10条评论

37

axios 1.x.x 版本将模块类型从 CommonJS 更改为 ECMAScript。

axios 0.x.x 版本的 index.js 文件
module.exports = require('./lib/axios');
axiox index.js文件的1.x.x版本
import axios from './lib/axios.js';
export default axios;

基本上,jest 运行在 Node.js 环境中,所以它使用遵循 CommonJS 规范的模块。 如果你想要使用 axios 的 1.x.x 版本,你需要将 JavaScript 模块从 ECMAScript 类型转换为 CommonJS 类型。 Jest 忽略 /node_modules/ 目录进行转换。

所以你必须覆盖 transformIgnorePatterns 选项。 有两种方法可以覆盖 transformIgnorePatterns 选项。

jest.config.js

如果你的 Vue 项目使用 jest.config.js 文件,你可以添加这个选项。

module.exports = {
  preset: "@vue/cli-plugin-unit-jest",
  transformIgnorePatterns: ["node_modules/(?!axios)"],
  ...other options
};

package.json

如果您的Vue项目使用 package.json 文件进行Jest配置,可以添加此选项。

{
  ...other options
  "jest": {
    "preset": "@vue/cli-plugin-unit-jest",
    "transformIgnorePatterns": ["node_modules\/(?!axios)"]
  }
}

这个正则表达式可以帮助您转换axios模块并忽略node_modules目录中的其他模块。


1
这对我没起作用。 - rcbevans
给我一些上下文。 - Junhyunny
我也一样。对我也没有用,我得到了相同的错误@Junhyunny SyntaxError:无法在模块外使用导入语句。 - quefro
@quefro 给我一些上下文信息。 - Junhyunny
在添加到 package.json 时出现了 found unknown escape character 的错误。 - basswaves
在添加到package.json时出现了found unknown escape character的错误提示。 - undefined

25

jest 版本更新至 v29 可以解决我的项目中的问题。可能是因为您使用了不兼容的 jest 版本。


5
太好了!终于让我解决了。从v27升级到v29。 - James
1
不行,我有最新版本,但它不起作用。 - SalahAdDin
1
感谢!jest 28.0.0: “Add support for package.json exports”解决了我的代码是"type": "commonjs"而axios 1.0默认导出是"type": "module"时出现的SyntaxError问题。 - yonran
但是,这个错误的原因是什么呢?有人知道根本原因吗? - undefined

16

快速修复

将npm运行测试脚本更新为

 "test": "react-scripts test",

 "test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!axios)/\"",

1
太棒了!!!这对我有用(我正在使用React) - Cristian
它对我起作用了。 - Sree Nath

12
这对我有用:
在你的jest.config.js中添加moduleNameMapper。
moduleNameMapper: {
    axios: 'axios/dist/node/axios.cjs',
},

对我有用。非常感谢 :) - Harsh Srivastava
你真是个救星啊,这应该是被接受的答案。 - Surya
这应该是第一名的答案。对我起作用。 - undefined

3

如果你在使用NestJs时遇到了这个问题,那么请升级你的package.json文件,使用以下版本的包。

 "jest": "^29.0.0" 

 "ts-jest": "^29.0.0"

3

我也遇到了同样的问题,但是我使用了 jest-mock-axios 库成功解决了这个问题。


3

我面临着同样的问题。首先使用变体(在package.json文件内):

"jest": {
    "moduleNameMapper": {
      "axios": "axios/dist/node/axios.cjs"
    }
  },

但是为了模拟我使用axios-mock-adapter。然后我得到了错误:

TypeError:mock.onGet不是一个函数

我将代码改为:

"jest": {
       "transformIgnorePatterns": [
          "/node_modules/(?!(axios)/)"
        ]
     }

这个解决方案可行。 版本:

  • "axios": "^1.4.0"

  • "axios-mock-adapter": "^1.21.5"

  • "@types/axios-mock-adapter": "^1.10.0"


2
在我的情况下,我必须将以下行添加到jest配置文件中的moduleNameMapper对象中:
axios: '<rootDir>/node_modules/axios/dist/node/axios.cjs',

1

我遇到了类似的问题,但是错误是由jest引起的。 所有尝试导入axios的测试都失败并抛出相同的异常:

Test suite failed to run
    Jest encountered an unexpected token
    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
    Here's what you can do:
     • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html
    Details:
    /monorepo/node_modules/axios/index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import axios from './lib/axios.js';
                                                                                             ^^^^^^
    SyntaxError: Cannot use import statement outside a module
      1 | import { describe, expect, it } from '@jest/globals'
    > 2 | import axios from 'axios'

解决方案很简单,只需告诉jest需要使用babel转换axios:
const esModules = ['lodash-es', 'axios'].join('|')

# add these entries in module.exports
transform: {
  [`^(${esModules}).+\\.js$`]: 'babel-jest',
},
transformIgnorePatterns: [`node_modules/(?!(${esModules}))`],

注意:我正在使用 Quasar Vue,这是他们的实现。

谢谢。目前我已经通过降级Axios来在本地解决了这个问题,但我会尝试这个方法看看是否有帮助。 - knirirr
这对我没用。 - rcbevans
您要将此添加到哪个文件? - zaitsman
In jest.config.js - Covik

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