5

我开发了一个 JavaScript 插件,可以包含在我们客户的网站上。我创建的插件依赖于一些外部库,它们被捆绑并作为一个大包交付给客户端:jQuery 1.8.2 和 KnockoutJS v3.0.0。

该插件在大多数站点上都可以正常运行,但是如果主机站点使用 RequireJS,我的包将无法加载,因为 KnockoutJS 会自动检测到 RequireJS 存在并尝试使用它。这是引发的错误:

Mismatched anonymous define() module

显然,我在 RequireJS 站点上找到了错误消息的“解释”。不幸的是,我不明白如何避免它。在我本地的 KnockoutJS 库副本中,我发现了有问题的行:

(function(factory) {
    // Support three module loading scenarios
    if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
        // [1] CommonJS/Node.js
        var target = module['exports'] || exports; // module.exports is for Node.js
        factory(target);
    } else if (typeof define === 'function' && define['amd']) {
        // [2] AMD anonymous module
        define(['exports'], factory);
    } else {
        // [3] No module loader (plain <script> tag) - put directly in global namespace
        factory(window['ko'] = {});
    }
}

如果我手动编辑此文件,使条件 [2] 永远不会执行,并且每次只执行条件 [3],那么一切正常。当然,我不想这样做,因为它需要我编辑一个外部库,我希望它保持原始状态,以便以后升级它。

我感觉可能有办法让这项工作,我只是不明白 RequireJS 是如何工作的。显然,KnockoutJS 试图与 RequireJS 配合得很好,但就我而言,它失败了。对我来说,在这种情况下,即使存在 RequireJS,我也不需要 KnockoutJS 来使用它。

我怎样才能让这两个库并排工作?

编辑

我无法控制何时加载我的库与主机站点已加载的所有其他库。事实上,大多数时候我的插件都会被包含在内,它将由没有网络开发经验的人使用糟糕的所见即所得平台(如 WordPress、Webs.com 或 Weebly),所以有时我的脚本标签可能会出现在头顶元素,其他时候它可能包含在某处的 body 元素中。

另外,需要明确的是,我的库不使用 RequireJS。碰巧我们的一位客户尝试使用我的库确实使用了 RequireJS,当我的库被包含时,KnockoutJS(与我的库捆绑在一起,但尚未在主机站点上)抛出异常,因为它认为它需要用 RequireJS 注册自己(或者至少这是我对异常的猜测)。

虽然原则上,我并不反对按需加载我的代码所依赖的库,但事实是它会给我的用户带来缓慢、糟糕的体验,因为加载它们需要额外的请求/响应周期。

4

1 回答 1

4

好吧,最简单的事情可能是在requirejs之前加载淘汰赛。ko 将不再检测到 require 的存在,并将使用选项 [3]。如果你不能这样做,另一个选择是在需要层次结构中添加你的插件和 ko 文件。

因此,假设您的插件看起来像这样:

(function(ko){

//stuff
ko.applyBindings({});

})(ko) 

您需要将其更改为:

require([
    "knockout-3.0.0.js" // this should be the url you use for knockout
    ], function(ko){
       //stuff
       ko.applyBindings({});
})

并且不要将 knockout.js 文件作为单独的标签加载。Require 将处理加载。当然,服务器必须仍然能够提供“knockout-3.0.0.js”网址。这就是 require 的工作方式。它会加载您作为 require 的数组参数中的元素传递的任何 url,并将它们作为参数返回的内容传递给函数。

如果您需要将插件文件和 ko 文件压缩/捆绑到一个文件中,您可以使用 reuquirejs 压缩器/优化器 ( http://requirejs.org/docs/optimization.html )。它将导航依赖关系树并仅输出一个包含所有模块的 js 文件。这里有一个怪癖:您需要删除 .js 扩展名才能使缩小器工作,阅读更多关于它的文档,我刚刚提到它是为了省去一些麻烦。

此外,可以在此处找到有关如何将 ko 与 require 一起使用的更多文档:http: //knockoutjs.com/documentation/amd-loading.html

编辑,操作编辑后:

好的,所以在这种情况下,您应该创建一个单独的范围,您可以在其中做您想做的事情。您需要将 ko 代码复制到文件中,但像​​这样您至少会得到一个文件。

所以,首先创建一个范围:

(function(){

})()

然后在里面复制ko代码:

(function(){

//ko code here, should be a single, minified line

})()

然后你需要欺骗 ko 使用选项 3,所以这样做:

(function(){

var define = null; //so define will no longer be a function, don't forget the var
var require = null;
//ko code here, should be a single, minified line

})()

或者,如果您不希望 ko 可用于整个页面,您可能还希望在上述步骤中重新分配窗口。

现在添加您的插件代码:

(function(){

var define = null; //so define will no longer be a function, don't forget the var
var require = null;
//ko code here, should be a single, minified line

//plugin code here;

})()
于 2013-11-01T22:19:22.630 回答