通过使用RequireJS和维护jQuery依赖项来加载Highcharts的shim

19

我正在尝试使用RequireJS中的shim加载Highcharts库。但是,当Highcharts加载时,它会抛出一个异常,因为它无法访问其所依赖的jQuery方法。

require配置看起来像这样:

require.config({
    baseUrl: "js",

    shim: {

        'libs/highcharts/highcharts.src.js': {
            deps: ['jquery'],
            exports: function(jQuery)
            {
                this.HighchartsAdapter = jQuery;

                return this.Highcharts;
            }
        }
    }
});

抛出的异常是:

Uncaught TypeError: undefined is not a function

该内容与以下代码行有关:

dataLabels: merge(defaultLabelOptions, {
问题出在merge函数调用上,该函数最终映射回jQuery(或其他Highcharts支持的适配器;但我只是使用jQuery)。
我不确定如何确保Highcharts通过RequireJS和shim访问到jQuery。
有人曾经将RequireJS和Highcharts结合在一起使用过吗?我想问题不仅限于Highcharts,还包括具有其他依赖项的任何库。
提前感谢任何关于此问题的建议或指向正确方向的指引!
为了进一步说明情况,希望熟悉require.js或shim的人能够无需过于熟悉highcharts就能提供帮助,以下是设置Highcharts中这个merge方法的一些源代码。
var globalAdapter = win.HighchartsAdapter,
adapter = globalAdapter || {},

// Utility functions. If the HighchartsAdapter is not defined, 
// adapter is an empty object
// and all the utility functions will be null. In that case they are 
// populated by the
// default adapters below.

// {snipped code}

merge = adapter.merge

// {snipped code}

if (!globalAdapter && win.jQuery) {
    var jQ = win.jQuery;

    // {snipped code}

    merge = function () {
        var args = arguments;
        return jQ.extend(true, null, args[0], args[1], args[2], args[3]);
    };

    // {snipped code}
}
win 对象是一个引用,最初设定为 window。因此,我认为在 shim 的导出方法中添加 window.jQuery = jQuery; 将使 highcharts 拾取 jQuery 引用;但实际上并没有达到这个效果。

总之,任何见解、消息、建议或嘲笑都将不胜感激——我完全迷失了方向,并开始质疑在浏览器 JavaScript 中尝试实现 AMD 包系统是否真的值得。

接受下面的 pabera 的答案后,我认为更新我的问题以反映他的答案如何帮助我的解决方案(虽然基本上是他的答案)。

RequireJS 使用 "paths" 找到不支持 "AMD" 的库并加载它们到您的页面上。"shim" 对象允许您为在路径中定义的库定义依赖项。在 requirejs 尝试加载相关脚本之前,必须先加载这些依赖项。

"exports" 属性提供了一种机制来告诉 requirejs 如何确定库是否已加载。对于像 jquery、backbone、socketio 等核心库,它们都导出某些 window 级别的变量 (Backbone, io, jQuery$ 等)。您只需将该变量名称作为 "exports" 属性即可,requirejs 将能够确定库何时已加载。

完成定义后,您可以像预期的那样使用 requirejs 的 "define" 函数。

这是我的示例 "require.config" 对象:

require.config({
    baseUrl: "/js/",

    paths: {
        jquery: 'jquery',
        socketio: 'http://localhost:8000/socket.io/socket.io', //for loading the socket.io client library
        highcharts: 'libs/highcharts/highcharts.src',
        underscore: 'libs/underscore',
        backbone: 'libs/backbone'
    },

    shim: {
        jquery: {
            exports: 'jQuery'
        },

        socketio: {
            exports: 'io'
        },

        underscore: {
            exports: '_'
        },

        backbone: {
            deps: ['jquery', 'underscore'],
            exports: 'Backbone'
        },

        highcharts: {
            deps: ['jquery'],
            exports: 'Highcharts'
        }
    }
});

正如pabera之前提到的那样,这是为Require.JS版本2.0.1准备的。

我希望有人能从中获益; 我知道它曾经让我困扰了一段时间; 所以通过发布这篇文章,希望我们能防止你撞在同一个墙上,避免你对着同一个地方砸头。

2个回答

28

我曾经遇到完全相同的问题,花了很多时间才看到您在这里的解决方案。然后我从头开始重新尝试,现在至少对我有效了。

requirejs.config({
    baseUrl:'/js/',
    paths:{
      jquery:'vendor/jquery',
      handlebars: 'vendor/handlebars',
      text: 'vendor/require-text',
      chaplin:'vendor/chaplin',
      underscore:'vendor/underscore',
      backbone:'vendor/backbone',
      highcharts: 'vendor/highcharts'
    },

    shim: {
      backbone: {
        deps: ['underscore', 'jquery'],
        exports: 'Backbone'
      },
      underscore: {
        exports: '_'
      },    
      highcharts: {
        exports: 'Highcharts'
      }    
    },
});

由于我使用了Chaplin在Backbone之上,因此我在路径属性中包含了更多的文件。Highcharts的结构与Backbone类似,所以我认为可以以同样的方式加载它。现在对我来说已经可以工作了。正如你所看到的,我已经在路径属性中引入了highcharts,以后再导出它为一个shim。

也许这可以帮助你,否则我们可以更进一步地贡献来解决你的问题。


我会尝试一下,看看我能得到什么结果;感谢您的回复! - Jim Rubenstein
我使用 require.js 2.0.1,以防重要。祝你好运。 - pabera
1
我改用普通的require.js(而不是w / jquery),并使用了jquery shim,结合您对路径/ shims的解释/示例。在进一步阅读文档后,现在我明白了发生了什么 - 非常感谢! - Jim Rubenstein
为什么不把你的baseUrl设置为'/js/vendor/'呢? - Adam Grant

2
尽管jQuery可以用作AMD模块,但它仍会导出到window对象,因此任何依赖全局jQuery$的脚本仍然可以正常工作,只要jQuery先加载即可。
你尝试过设置路径吗? jQuery很有趣,因为虽然RequireJS文档鼓励您不要按名称命名模块,但jQuery实际上确实这样做了。
来自jQuery源代码
if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
    define( "jquery", [], function () { return jQuery; } );
}

这意味着您需要告诉RequireJS在哪里找到“jquery”。因此:
require.config({
    paths: {
        'jquery': 'path/to/jquery'
    }
});

如果你想知道为什么jQuery以这种方式进行注册,那么在源代码中有一个相当大的注释对此进行了更详细的解释。


我实际上下载了带有jQuery的require.js代码在这里,认为这至少是“使用require.js加载jquery的建议方式”,所以我正在使用它。据我所知,通过使用该下载,require.js源基本上处理了jQuery,这应该(我猜)消除了使用“路径”设置jquery路径或shimming jquery的需要。 - Jim Rubenstein

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