简体   繁体   English

加载第二个版本的jQuery和其他库

[英]Loading a second version of jQuery, and other libraries along with it

I'm making a widget that consists of a snippet of code to drop in your site that will then pull in content via js. 我正在制作一个由一段代码组成的小部件,该代码段可放入您的网站,然后通过js提取内容。 Here's an example snippet: 这是一个示例片段:

<div data-token="bc1cea6304e8" id="my-widget">
    <script src="http://localhost:8080/assets/eg-widget.js" type="text/javascript"></script>
</div>

I'm doing a test to check if the page already has jQuery, and if so, that the version is at least 1.5. 我正在做一个测试,以检查页面是否已经有jQuery,如果是,则该版本至少为1.5。

if (typeof jQuery == 'undefined' || isVersion("1.5", ">")) {

    var script_tag = document.createElement('script');
    script_tag.setAttribute("type", "text/javascript");
    script_tag.setAttribute("src",
        "http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js");

    // Try to find the head, otherwise default to the documentElement
    (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);

    if (script_tag.readyState) {
        script_tag.onreadystatechange = function () { // For old versions of IE
            if (this.readyState == 'complete' || this.readyState == 'loaded') {
                scriptLoadHandler();
            }
        };
    } else { // Other browsers
        script_tag.onload = scriptLoadHandler;
    }
} else {
    // The jQuery version on the window is the one we want to use
    jQueryEg = window.jQuery;
    scriptLoadHandler();
}

In either case, we set a variable jQueryEg to the jQuery we decide to use so that we can avoid conflicts. 无论哪种情况,我们都将变量jQueryEg设置为我们决定使用的jQuery,以便避免冲突。

If jQuery is not already loaded, everything is dandy. 如果尚未加载jQuery,则一切正常。 But if an older version is loaded, we run into conflicts when trying to load other libraries such as jQuery-ui. 但是,如果加载了旧版本,则在尝试加载其他库(如jQuery-ui)时会发生冲突。

To do this, we set window.jQuery to our newly loaded jQuery so that when we load jquery-ui and bootstrap.js, their references to window.jQuery or $ point to the correct version. 为此,我们将window.jQuery设置为新加载的jQuery,以便在加载jquery-ui和bootstrap.js时,它们对window.jQuery或$的引用指向正确的版本。

The problem is that sometimes the other parts of the page are calling jQuery at the same time that we've set window.jQuery to our version which causes problems. 问题在于,有时在我们将window.jQuery设置为我们的版本的同时,页面的其他部分正在调用jQuery,这会导致问题。

Any thoughts on how we can avoid these conflicts? 关于如何避免这些冲突的任何想法?

jQueryEg = window.jQuery.noConflict(true);
window.jQueryEg = jQueryEg;

// jquery-ui reference window.jQuery so we need to set that to our new jquery for a sec

if (jQueryEg.ui == undefined || jQueryEg.ui.datepicker == undefined) {
    var otherjQuery = window.jQuery;
    window.jQuery = jQueryEg;

    var script_tag = document.createElement('script');
    script_tag.setAttribute("type", "text/javascript");
    script_tag.setAttribute("src",
        "//ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js");
    (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);

    script_tag.onload = function () {
        window.jQuery = otherjQuery;
        main();
    };

}

Once I run into a similar issue . 有一次我遇到类似的问题 Looking at the jQuery-UI code, I noticed that it's all wrapped in an immediately invoked function expression (or maybe I wrapped it myself? I can't remember): 在查看jQuery-UI代码时,我注意到它们全部包装在立即调用的函数表达式中(或者我自己包装了它?我不记得了):

( function ( jQuery, undefined ){
  // Code here...
})( jQuery );

to create private scopes . 创建私人范围 So my solution was to 所以我的解决办法是

  1. Save the current jQuery to jQuery_OLD 将当前的jQuery保存到jQuery_OLD
  2. Load the new jQuery version 加载新的jQuery版本
  3. Load jQuery-UI, and let it grab the compatible version 加载jQuery-UI,并使其获取兼容版本
  4. Restore old jQuery 恢复旧的jQuery

So the following gives the idea 所以下面给出了这个想法

<script src="jquery-1.4.js"></script>
<script>
    var jQuery_1_4 = jQuery.noConflict();
</script>
<script src="jquery-1.8.js"> </script>
<!-- load jquery UI -->
<script src="jquery-ui.js"> </script>
<!-- restore window.jQuery -->
<script>
    jQuery = jQuery_1_4;
</script>

Having run into this exact situation before, in the end the determination was what you probably already know, and don't want to hear: There is simply no good way to avoid all edge-cases when loading multiple versions of external libraries like that, due to the reasons you have already specified. 之前遇到过这种确切的情况,最终确定是您可能已经知道的,并且不想听到:加载这样的外部库的多个版本时,根本没有避免所有边缘情况的好方法,由于您已经指定的原因。 A summary of the complications involved are: 所涉及并发症的摘要是:

  • The main problem, of course: that the loading of external scripts is asynchronous by its nature, and there is no "just before execution" / "just after execution" callback to ensure that everything is wrapped nicely. 当然,主要的问题是:外部脚本的加载本质上是异步的,并且没有“执行前” /“执行后”回调以确保所有内容都被包装好。 ie: there is no way to "surround" dynamically-loaded code. 即:没有办法“包围”动态加载的代码。
  • Scripts are executed in-order when placed in the document directly, but there is no way to conditionally load one based on something determined by another. 将脚本直接放置在文档中时会按顺序执行脚本,但是无法根据另一个脚本确定的条件来有条件地加载一个脚本。
  • Finally, for user-friendliness reasons (ie: allowing random people across the web to use your snippet with zero code knowledge and no support staff), restrictions such as "ensure this snippet is pasted before any other scripts!" 最后,出于用户友好的原因(即:允许网络上的随机人员使用零代码知识且无需支持人员的情况下使用您的代码段),例如“确保所有其他脚本之前粘贴此代码段!”这样的限制! are right out. 马上出来。 Even if they could work (*and they won't, really see the other two points), they would be ignored, especially by those who don't have full control over their pages. 即使它们可以工作(*并且他们不会,实际上看不到其他两点),它们也会被忽略,尤其是那些对页面没有完全控制权的人。

Unfortunately, the only answer is the obvious one: Host modified versions of the libraries on your own servers. 不幸的是,唯一的答案是显而易见的:在自己的服务器上托管库的修改版本。

Of course, you don't need to serve these versions all the time, so you can still benefit from the use of Google's CDN. 当然,您不需要一直提供这些版本,因此您仍然可以受益于Google CDN的使用。 Meanwhile, you can still use your own CDN to deliver the modified versions. 同时,您仍然可以使用自己的CDN交付修改后的版本。 The main guidelines to follow are: 要遵循的主要准则是:

  1. Run your script after the entire page is loaded (using onDOMReady, etc), to ensure the conflict doesn't happen "after" your own script is included. 加载整个页面后(使用onDOMReady等)运行脚本,以确保在包含您自己的脚本之后“不会”发生冲突。
  2. Determine if a conflict is possible. 确定是否可能发生冲突。 Serve your modified versions in those cases, and serve from a public CDN otherwise. 在这种情况下,请提供修改后的版本,否则,可以通过公共CDN提供服务。
  3. Check for compatibility with other libraries often. 经常检查与其他库的兼容性。 Your code will evolve over time, just as the libraries you use will. 您的代码将随着时间的推移而发展,就像您使用的库一样。 The "determine if a conflict is possible" step needs to be accurate for this to work. “确定是否可能发生冲突”步骤必须准确才能起作用。 Err on the side of caution: serve your own version if you are unsure. 谨慎一点,请注意:如果不确定,请提供您自己的版本。
  4. Always provide an easy option for the paster to say "always use the modified version", in case your detection fails somehow. 始终为粘贴程序提供一个简单的选项,让其说“始终使用修改后的版本”,以防检测失败。
  5. Always serve compressed , uglified versions of your scripts, with appropriate cache headers , to reduce the load on your own servers. 始终提供压缩的丑陋的脚本版本以及适当的缓存头 ,以减少您自己的服务器上的负载。

You'll usually find that the number of hits on your own server are actually quite minimal, comparatively. 通常,您通常会发现,相对而言,您自己的服务器上的匹配次数实际上很少。 As always, don't trust me: keep statistics on your own, real-world scenarios! 与往常一样,不要相信我:在您自己的真实场景中保存统计信息!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM