使用Require.js在页面上运行Q.

时间:2014-11-25 00:31:36

标签: javascript namespaces requirejs shared-libraries q

我正在尝试在利用 Q库的网页上运行小部件。不幸的是,该页面还使用嵌入 require.js AddThis小部件并导致冲突。具体来说,当一起运行时,控制台中会显示以下两条错误消息:

未捕获的ReferenceError:Q未定义
未捕获的错误:匿名的define()模块不匹配

不幸的是,我无法控制AddThis小部件的使用。但是,我确实可以使用Q控制嵌入式应用程序。是否有一个JavaScript模式可以实现命名空间Q库,以便它不会与require.js冲突?

这是一个演示问题的简单示例:

<!doctype html />
<html>
<head>
  <script src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.15/require.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/q.js/0.9.2/q.min.js"></script>
</head>
<body>
   <script>
     var called = function() {
       var deferred = Q.defer();

       console.log("Q called successfully");

       deferred.resolve();
       return deferred.promise;
     }

     Q.fcall(called);
   </script>
</body>
</html>

1 个答案:

答案 0 :(得分:2)

我将在前言中说我不熟悉“AddThis”,并且不会称自己为“需要”的专家,但我将尝试解决您在这种情况下遇到的各种问题

首先,当Q发现require时,它不会将自己置于全局命名空间中,而只是使用Q模块调用define。这将在require中创建一个匿名模块,该模块通过使用该文件的路径调用require来加载。这是可能在非浏览器环境中使用的模块的常见模式。当你注释掉那个块时,它会转到“脚本”模块加载器,在那里它创建一个Q模块的实例并在self上设置它。在浏览器中,这显然是窗口别名。

那么,我们如何解决这个问题而不在q.js中注释掉模块垃圾的部分内容?

您应该能够使用Require的shim configuration将Q导出到全局范围,如下所示:

require.config({
    shim: {
        Q: {
            exports: "Q"
        }
    }
});

但这有两个问题。首先,你无法控制require配置,对吧?它由“AddThis”插件加载。其次,从shim配置中导出Q对Q来说似乎不起作用,可能是因为Q在内部使用“define”(要求说内部使用“define”的脚本可能没有正确填充。这也可能是触发你的“匿名的define()模块“错误”不匹配。奇怪的是,在Q的github上似乎没有任何其他SO问题或问题关于这种缺乏补偿能力的问题。我不确定Q是做错了什么还是我疯了。也许对模块垫片有更多了解的人可以对此发表评论。

无论如何,你不能在这里垫片。你应该可以这样做:

if ( require ){
    require(['path/to/Q'],function(Q){ window.Q = Q; });
}

如果需要存在,这将明确要求Q并将其保存到窗口变量中,以便您可以在任何地方使用它。

然而,这也有问题。这里的“path / to / Q”将相对于该require配置中设置的任何baseUrl。所以,如果“AddThis”将baseUrl设置为该插件的一些奇怪路径,那么你很难找到Q,那么你可能必须解决这个问题。

您可以使用Require的multiversion功能设置自己的配置,指定您自己的baseUrl:

if ( require ){
    var myRequire = require.config({
        baseUrl: '/my/local/root',
        paths: {
            Q: 'path/to/Q'
        }
    });
    myRequire(['Q'],function(Q){
        window.Q = Q;
        bootstrapMyApp();
    });
}
else {
    bootstrapMyApp();
}

这是完全未经测试的,但似乎它可能有效!