不匹配的匿名define()模块

148
我第一次浏览我的webapp时(通常在禁用缓存的浏览器中),遇到了这个错误。

错误:匿名定义模块不匹配:function (require) {

HTML

<html>
   .
   .
   .
   <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
   <script> var require = { urlArgs: "v=0.4.1.32" }; </script>
   <script data-main="assets/js/main" src="assets/js/libs/require.js"></script>
   <script src="assets/js/ace/ace.js?v=0.4.1.32"></script>
   </body>
</html>

JS:

$(function () {
    define(function (require) {
        // do something
    });
});

有人知道这个错误具体是什么意思,为什么会发生吗?
在 GitHub 的问题页面上有一个关于它的源文件和一个简短讨论
8个回答

156

根据文档,如 AlienWebguy 所说,require.js 可能会出现问题,原因有:

  • 在自己的脚本标签中具有匿名定义(“使用没有字符串 ID 的 define() 调用的模块”)(我认为实际上他们指的是全局范围内的任何地方)
  • 存在名称冲突的模块
  • 使用加载器插件或匿名模块,但不使用 require.js 的优化程序将它们打包

在将使用 browserify 构建的捆绑包与 require.js 模块一起包含时,我遇到了这个问题。解决方法是:

A. 在加载 require.js 之前,使用脚本标签加载非 require.js 独立捆绑包,或者

B. 使用 require.js(而不是脚本标签)加载它们。


2
名称冲突是一个常见的问题。 - Julio Marins
2
另一个可能的解决方案,在某些特殊情况下使用匿名模块,是覆盖 requirejs.onError 函数,以防止 requirejs 抛出默认错误异常,从而停止执行后续模块或代码。 - xtrm
2
刚刚添加了一个拉取请求(https://github.com/requirejs/requirejs/pull/1763),以放宽确切的情况。我认为这是当今非常普遍的问题。 - Bob S
1
谢谢您告诉我在之前加载它们!我不知道为什么这个提示不在 requirejs 的官方文档中... 这就是 Stack 发挥作用的地方。 - Tobias Feil

18

在开始使用require.js时,我遇到了问题,作为初学者,文档可能像希腊语一样难懂。

我遇到的问题是,大多数初学者示例使用“匿名定义”,而您应该使用“字符串ID”。

匿名定义

define(function() {
        return { helloWorld: function() { console.log('hello world!') } };
 })
    
  
define(function() {
        return { helloWorld2: function() { console.log('hello world again!') } };
 })
使用字符串ID进行定义
define('moduleOne',function() {
    return { helloWorld: function() { console.log('hello world!') } };
})

 define('moduleTwo', function() {
      return { helloWorld2: function() { console.log('hello world again!') } };
})

当你使用字符串 ID 进行定义时,你将避免在尝试使用模块时出现该错误:

require([ "moduleOne", "moduleTwo" ], function(moduleOne, moduleTwo) {
    moduleOne.helloWorld();
    moduleTwo.helloWorld2();
});

1
(仅供参考)这种方法存在一些缺点,文档中有描述:“包含模块名称的define()调用通常是由优化工具生成的……自己命名模块会使模块不太容易移植……最好避免为模块编写名称,让优化工具自动生成模块名称。” 这也是为什么初学者示例中排除了列出名称的原因,以及在这个GitHub线程中提到的。 - Mark G.

15
我之前遇到了一个错误,是因为我使用一个 script 标签直接引入 requirejs 文件以及其他库。这些库(例如 lodash)使用了一个与 require 的 define 函数相冲突的 define 函数。requirejs 文件是异步加载的,我猜测其他库的 define 已经在 require 的 define 之前定义好了,所以才会出现冲突。
为了消除这个错误,请使用 requirejs 来引入所有其他的 js 文件。

结果发现很多库都做了这样的事情,或者至少使用/导出了这样的函数。我建议每个人 - 如果他们使用require - 使用require导入所有内容 :) - Andrey Popov

12

根据文档

如果您在HTML中手动编写了一个脚本标签来加载带有匿名define()调用的脚本,则可能会发生此错误。

如果您在HTML中手动编写了一个脚本标签以加载具有几个命名模块的脚本,但随后尝试加载一个匿名模块,该匿名模块最终与手动编写的脚本标记加载的一个名称模块具有相同的名称,则也会出现此错误。

最后,如果您使用加载器插件或匿名模块(调用define()而没有字符串ID的模块),但不使用RequireJS优化程序将文件组合在一起,则可能会出现此错误。 优化程序知道如何正确命名匿名模块,使它们可以与其他模块组合在一个优化的文件中。

避免此错误的方法:

  • 确保通过RequireJS API加载调用define()的所有脚本。不要手动编写在HTML中加载具有define()调用的脚本的脚本标记。

  • 如果手动编写HTML脚本标记,请确保它仅包括命名模块,并且不加载与该文件中某个模块同名的匿名模块。

  • 如果问题是使用加载器插件或匿名模块,但未使用RequireJS优化程序进行文件捆绑,请使用RequireJS优化程序。


3
这是一个匿名定义的模块吗? https://github.com/requirejs/example-multipage/blob/master/www/js/app/controller/c1.js - streetlight

9
现有的答案已经很好地解释了问题,但如果由于遗留代码无法使用或在 requireJS 之前包含您的脚本文件,那么一个稍微有些 hacky 的解决方法是在您的脚本标签之前从 window 范围中删除 require,然后在此后恢复它。在我们的项目中,这个方法被封装在服务器端的函数调用后面,但实际上浏览器看到的是下面这样的代码:
    <script>
        window.__define = window.define;
        window.__require = window.require;
        window.define = undefined;
        window.require = undefined;
    </script>
    <script src="your-script-file.js"></script>        
    <script>
        window.define = window.__define;
        window.require = window.__require;
        window.__define = undefined;
        window.__require = undefined;
    </script>

虽然不是最整洁的代码,但它似乎可以工作,并且已经省去了很多重构的工作。


5
千万不要这么做。在IE浏览器中无法正常工作。 - jcbdrn
2
在IE浏览器中,有时候即使require命令在那些变量被恢复之后才出现,使用requireJS包含的脚本仍然会在其window范围内缺少定义。我们从未成功地找出了这种情况发生的原因,因此我们放弃了这个hacky解决方案。 - jcbdrn
3
不仅在IE上会出现这种情况,我也看到它在其他平台上发生过。原因在于HTML规范确实提供了关于同步脚本执行顺序的保证,但这仅限于相对于其他同步脚本的执行顺序。它不保证相对于同步脚本(或反之)异步脚本的执行顺序。所以在这里所展示的代码中,任意两个script元素之间都可能会执行一个异步脚本。 - Louis
如果您有能力编辑导入的bundle js,您可以像这样包装整个内容:(function(){ var define = undefined; // UMD注册代码将不再找到全局的 'define'! // 生成的内容在此处 })() - Pete Thorne
谢谢,对于有很多团队的传统应用程序来说,这是理想的解决方案... :/ - Gabriel Anderson
我爱你兄弟。你是我的英雄! - Timotheus0106

5
请注意,一些浏览器扩展程序可能会向网页中添加代码。在我的情况下,我安装了一个名为“Emmet in all textareas”的插件,它与我的requireJs产生了冲突。请确保通过在浏览器中检查文档来避免向您的文档中添加任何额外的代码。

3

或者您可以采用以下方法。

  • 将require.js添加到您的代码库中
  • 然后通过该代码加载您的脚本

<script data-main="js/app.js" src="js/require.js"></script>

它将在加载require.js之后加载您的脚本。


0

我在一个基于require.js的项目中也看到了同样的浏览器控制台错误。如https://requirejs.org/docs/errors.html下所述的MISMATCHED ANONYMOUS DEFINE() MODULES,这个错误有多种原因,而在我的情况下最有趣的原因是:如果问题是使用加载器插件或匿名模块,但未使用RequireJS优化程序进行文件捆绑,请使用RequireJS优化程序。事实证明,在构建期间,Google Closure编译器被用来合并/缩小JavaScript代码。解决方案是删除Google Closure编译器,并改用require.js的优化器(r.js)来合并js文件。


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