在导入ECMAScript 6时出现“Uncaught SyntaxError:Cannot use import statement outside a module”错误。

1157

我正在使用ArcGIS JSAPI 4.12,并希望使用Spatial Illusions在地图上绘制军事符号。

当我将milsymbol.js添加到脚本中时,控制台会返回错误

Uncaught SyntaxError: Cannot use import statement outside a module`

所以我将type="module"添加到脚本中,然后它返回

Uncaught ReferenceError: ms is not defined

这是我的代码:

<link rel="stylesheet" href="https://js.arcgis.com/4.12/esri/css/main.css">
<script src="https://js.arcgis.com/4.12/"></script>
<script type="module" src="milsymbol-2.0.0/src/milsymbol.js"></script>

<script>
    require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/MapImageLayer",
        "esri/layers/FeatureLayer"
    ], function (Map, MapView, MapImageLayer, FeatureLayer) {

        var symbol = new ms.Symbol("SFG-UCI----D", { size: 30 }).asCanvas(3);
        var map = new Map({
            basemap: "topo-vector"
        });

        var view = new MapView({
            container: "viewDiv",
            map: map,
            center: [121, 23],
            zoom: 7
        });
    });
</script>

所以,无论我是否添加type="module",都会出现错误。然而,在Spatial Illusions的官方文档中,脚本中没有任何type="module"。我现在真的很困惑。他们如何在不添加类型的情况下让它正常工作?

文件milsymbol.js

import { ms } from "./ms.js";

import Symbol from "./ms/symbol.js";
ms.Symbol = Symbol;

export { ms };

3
我现在正在使用 Browserify,通过它我可以使用require()来包含任何模块。请查看这个视频 - Zeeshan Ahmad Khalil
18
这个问题在Stack Overflow的21,642,537个问题中,以浏览率计算,在前10名之列(可能来自搜索引擎点击)。它的历史平均每天有大约1800次浏览。 - Peter Mortensen
例如:npm install node-fetch@2.0,因为为什么要在3.0版本中破坏API。永远不要破坏模块化组件的API,扩展它,或者什么都不做,谢谢。 - NVRM
3
@PeterMortensen 可能是因为标题让它看起来比实际情况更加通用。 - user3840170
35个回答

703

3
是的。基本上,不要独立运行 TypeScript 脚本,而是将它们放入现有的 Angular 项目中,一切都会正常工作的;-) - wormsparty
4
@wormsparty逃离循环 - tejasvi88
添加"type": "module"对我很有效! - Haroon Hayat

594
我之所以出现这个错误,是因为我忘记在脚本标签内加上 type="module"
<script type="module" src="whatever.js"></script>

12
我花了好几个小时试图让一个导入工作。最终放弃了几周,回来后,你的一行注释解决了我的问题。谢谢你。 - Ryan D
你是为我们这些凡人铺路的神性!其他的答案真的吓到我了,但这个直截了当! - Martin Melichar
1
@RyanD,这在 MDN 文档的第二段中有提到,通常我都会去查看任何 JavaScript 文档 https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export - reggaeguitar
谢谢。你知道为什么如果我在package.json中添加"type": "module",它就不起作用吗? - undefined

224

看起来错误的原因是:

  1. 您当前在src目录中加载源文件,而不是dist目录中已构建的文件(您可以查看此处所示的预期分发文件)。这意味着您正在使用未经修改/未捆绑的本机源代码,导致出现以下错误:Uncaught SyntaxError: Cannot use import statement outside a module。这应该通过使用捆绑版本来解决,因为该软件包正在使用rollup创建一个bundle。

  2. 您得到Uncaught ReferenceError: ms is not defined错误的原因是模块有作用域限制,因为您正在使用原生模块加载库,所以ms不在全局作用域中,因此无法在下面的脚本标记中访问。

看起来您应该能够加载此文件的dist版本,以便在window上定义ms。请查看库作者的此示例,了解如何实现此操作。


1
谢谢您的回复,现在我知道我有错误的文件。我一直在寻找分发版本的文件,但没有结果。您知道获取分发版本的任何方法吗?非常感谢! - Jerry Chen
它可以在npm上下载(https://www.npmjs.com/package/milsymbol)。或者,您可以通过克隆repo并运行其中一个构建脚本来构建它。看起来有一个AMD构建脚本(https://github.com/spatialillusions/milsymbol/blob/master/package.json#L14),应该允许您直接将构建包`require`到您的代码中。 - Kai
4
我已通过npm下载,现在我有这个脚本:<script src="node_modules/milsymbol/dist/milsymbol.js"></script>,但控制台仍然返回Uncaught ReferenceError: ms is not defined。问题在于dist / milsymbol.js中未定义ms,它在src / milsymbol.js中定义,但需要type =“ module”并会导致范围问题。是否有任何解决办法?非常感谢! - Jerry Chen
2
如果这是实际意图,从/src引用它会怎样呢?例如,如果作者不打算公开类的属性... - Cristian E.

104

我通过将import替换为require来解决了我的问题:

// import { parse } from 'node-html-parser';
const parse = require('node-html-parser');

14
const {parse} = require('node-html-parser'); 对我起作用了。 - EReload
8
请问这是什么解释?为什么会起作用?请通过编辑(更改)您的答案来回复,而不是在评论中回复(不要包含“编辑:”,“更新:”或类似内容 - 答案应该看起来像是今天写的)。 - Peter Mortensen
在 Node 中导致此问题的确切软件。 - Greggory Wiley
4
这个问题是关于浏览器的。 - Sergei
1
如果你想保持老派的风格,这个回答在NodeJs中很有用。但它与问题无关。 - Michel El Hajj
显示剩余2条评论

83

解决与上述问题相关的冲突有几种常见方法

1. 第一种:在脚本中包括type=module

    <script type="module" src="milsymbol-2.0.0/src/milsymbol.js"></script>

这是修复问题的最推荐方法。通过添加 type="module" 属性,您告诉浏览器该脚本应被视为 ECMAScript 模块,并且应使用适当的规则来解析依赖项和执行代码。

2. 第二步:在 node.js 中,将其添加到你的 package.json 文件中

    {
       
        "type": "module",
       
    }

重新启动项目: npm start

3. 第三步:将 import 替换为 required

试试这个

import { parse } from 'node-html-parser';
parse = require('node-html-parser');

否则尝试这个。
//import { parse } from 'node-html-parser';
parse = require('node-html-parser');


3
如果这三个都不起作用怎么办?我想要一个简单的api.js文件,其中包含大量可重复使用的全局函数,我不想每次都逐个导入。例如:<script id="apijs" src="%PUBLIC_URL%/api.js"></script> - NeoTechni
这三种方式是AND还是OR?如何在NextJS中使用它们? - LonelySoul
1
package.json 中添加 "type": "module" 可以与 node v18 一起使用。 - Yves Dorfsman
@LonelySoul 这些是最常见的三种解决上述问题冲突的方法。 - loopassembly

61

在添加 type="module" 到脚本之前,我也遇到了同样的问题。

之前代码是这样的:

<script src="../src/main.js"></script>

并在将其更改为之后

<script type="module" src="../src/main.js"></script>

它完美地工作了。


41
在执行此操作时出现CORS。 - Shreyan Mehta
5
这句话的意思是您正在从另一个域请求数据。您可以通过在您的头信息中添加Access-Control-Allow-Origin: * 来解决这个问题。您可以查看MDN关于CORS的文档,网址为https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests。 - Desire Kaleba
6
我了解 CORS,问题是这些是我的本地文件。 - Shreyan Mehta
8
您需要将脚本放在一个HTTP服务器上,浏览器使用HTTP请求来加载ES6模块,服务器需要在响应头中返回一个CORS以允许您的来源。 - danilo
2
最简单的方法:您可以使用http-server:https://dev59.com/questions/8m025IYBdhLWcg3wT0Lq#23122981 - danilo
这个答案已经被给出了:https://dev59.com/A1MH5IYBdhLWcg3wzzEe#58679392 - Vega

58

适用于 Node 12。此答案不再针对新的 Node 版本进行维护。欢迎评论提供更新版本的解决方案。

我通过以下方法解决了这个问题:

在浏览器中使用 ECMAScript 6 模块时,请在文件名中添加 .js 扩展名,并在脚本标签中加入 type = "module"

在 Node.js 环境中使用 ECMAScript 6 模块时,请在文件名中使用扩展名 .mjs ,并使用以下命令运行文件:

node --experimental-modules filename.mjs

注:此篇文章是在 node12 是最新的 LTS 版本时编写的,不适用于 node 14 LTS。


6
模块:ECMAScript模块:启用 https://nodejs.org/api/esm.html#esm_enabling - noobninja
8
不再需要这样做了。只需在 package.json 文件中添加 "type": "module",一切都会按预期工作。(文件名扩展名使用 .js) - Chris Perry
1
我们也可以使用.cjs文件。 - NVRM

33

我不知道这是否已经显而易见。我想指出,就客户端(浏览器)JavaScript而言,您可以将type="module"添加到外部和内部js脚本。

比如,您有一个文件'module.js':

var a = 10;
export {a};

您可以在外部脚本中使用它,其中您可以进行导入,例如:

<!DOCTYPE html><html><body>
<script type="module" src="test.js"></script><!-- Here use type="module" rather than type="text/javascript" -->
</body></html>

test.js:

import {a} from "./module.js";
alert(a);

您也可以在内部脚本中使用它,例如:
<!DOCTYPE html><html><body>
<script type="module">
    import {a} from "./module.js";
    alert(a);
</script>
</body></html>

值得一提的是,对于相对路径,您不能省略"./"字符,即:
import {a} from "module.js";     // this won't work

对于那些在Rails 7中遇到问题的人。我发现添加type="module"就像这样<%= javascript_include_tag 'someScript', type: "module" %>,其中app/javascript/someScript.js。我不明白这就像一个脚本标签一样。这将问题移动到了Uncaught TypeError: Failed to resolve module specifier "ol/Map". Relative references must start with either "/", "./", or "../".`。 - Greg

23
如果您想使用 import 而不是 require() 导入模块,需要在 package.json 文件中更改或添加 type 的值为 module。

例如:

package.json 文件

{
  "name": "appsample",
  "version": "1.0.0",
  "type": "module",
  "description": "Learning Node",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Chikeluba Anusionwu",
  "license": "ISC"
}
import http from 'http';

var host = '127.0.0.1',
    port = 1992,
    server = http.createServer();

server.on('request', (req, res) => {
  res.writeHead(200, {"Content-Type": "text/plain"});
  res.end("I am using type module in package.json file in this application.");
});

server.listen(port, () => console.log(
    'Listening to server ${port}. Connection has been established.'));

22

对我来说,这是由于没有将库(具体而言是 typeORM )引用到 src 文件夹下的 ormconfig.js 文件中的 entities 键中,而是引用到了 dist 文件夹下 ...

   "entities": [
      "src/db/entity/**/*.ts", // Pay attention to "src" and "ts" (this is wrong)
   ],

取代

   "entities": [
      "dist/db/entity/**/*.js", // Pay attention to "dist" and "js" (this is the correct way)
   ],

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