Using Multiple Versions of jQuery with Require.js

2019-04-12 04:41发布

问题:

I have a situation where I must have a two versions of jQuery running on the same page(Basically, there is a website running 1.4.2 and I have a bookmarklet that runs scripts that need 1.8.2 I know this is not a good idea but I'm stuck with it for now).

The existing version is 1.4.2 in one and the newer version needed is 1.8.2.

I am using require.js and have seen a post in this question here but don't quite understand what'a the best way to go:

In my case I have a module main.js:

(function () {
var root = this;

require.config({
    baseUrl: "http://localhost:9185/scripts/app/"      
});

define3rdPartyModules();
loadPluginsAndBoot();

function define3rdPartyModules() {
    define('jquery', [], function () { return root.jQuery.noConflict(true); });              
    define('ko', [], function () { return root.ko; });       
}

function loadPluginsAndBoot() {      
    requirejs([], boot);
}

function boot() {        
    require(['bootStrapper'], function (bs) { bs.run(); });
}
})();

and then some other modules that look similar to this:

define('bootStrapper', ['jquery', 'presenter', 'repository', 'dataPrimer'],
function ($, presenter, repository, dataPrimer) {
    //some stuff here

I'm am new to requirejs and am loading it before main.js is loaded using version 1.4.2 like this:

 $.getScript("http://localhost:9185/bundles/jsextlibs?v=GOyDBs-sBDxGR5AV4_K-m-   OK9DoE0LGrun5FMPyCO9M1", function () {     
    $.getScript("http://localhost:9185/Scripts/lib/require.js", function () {        
        $.getScript("http://localhost:9185/bundles/jsapplibs?v=9TJUN0_624zWYZKwRjap4691P170My5FUUmi8_fzagM1");
        $.getScript("http://localhost:9185/Scripts/main.js");
    });
});

Can someone please show me how to modify my code so that all my modules will be able to use version 1.8.2 without interfering with the code already running on 1.4.2.

Thanks

Davy

回答1:

var reqOne = require.config({
context: "version1",
baseUrl: 'scripts/',
paths: {
    jquery: 'lib/jquery.min',
}
});

var reqTwo = require.config({
    context: "version2",
    baseUrl: 'scripts/',
    paths: {
        jquery: 'lib/jquery.modern',
    }
});

reqOne(["helper/util"], function(require,util) {
        //This function is called when scripts/helper/util.js is loaded.
            //If util.js calls define(), then this function is not fired until
                //util's dependencies have loaded, and the util argument will hold
                    //the module value for "helper/util".
//                    intheutil(); //This was done
                    console.log('util loaded');
});


reqOne(['require','jquery'],function(require,$){
    console.log( $().jquery );
});

reqOne(['require','jquery'],function(require,jq){
    console.log( jq().jquery );
});


reqOne(['require','jquery'],function(require,$){
    console.log( $().jquery);
});

reqTwo(['require','jquery'],function(require,$){
    console.log( $().jquery );
});

console.log('If no errors mean success!');

The above is what i used in main.js. For full implementation detials please see my implementation in github. github.com.

Here jquery.min is the jquery version 1.x and jquery.modern is the jquery version 2.x

I have used console.log. So check the example with Browser console enabled. The above answer is based on the docs of Require.js. So i think it must be the solution for your case.

Here is my referrence. Require.js.



回答2:

I had a near-identical problem that I managed to solve using a similar method to Ajeeb K.P, with a few key differences. (Ajeeb's process didn't actually work for me, & consistently failed when using a jQuery CDN).

Essentially, I created 2 require.config instances, each with a different version of jQuery defined in the properties (kept DRY using a common require.config object which I merged each specific instance into). When either require.config instance is called (i.e. "passed to require" as the RequireJS API puts it), the code within the callback function runs an IIFE that receives jQuery.noConflict(true) as a $ parameter. Any code run within the IIFE - including modules require'd - runs the version of jQuery defined in the require.config instance initially passed to require.

Here's the code:

/*
 * For merging each separate require.config object with a "common RequireJS config
 * properties" object. Meant to avoid e.g. baseUrl, common libs etc. between the 2 
 * (lodash cannot be used for this, as it's not yet loaded until all this completes)
 */ 
var mergeObjs = function mergeObjs(objIn1, objIn2) {
    var conglomerateObj = {};
    Object.keys(objIn1).forEach(function(item) {
        conglomerateObj[item] = objIn1[item];
    });

    return (function mergeIn(o1, o2) {
        Object.keys(o2).forEach(function(key) {
            if (typeof o1[key] === 'undefined') {
                o1[key] = o2[key];
            } else if (typeof o1[key] === 'object' && typeof o2[key] === 'object') {
                o1[key] = mergeIn(o1[key], o2[key]);
            }
        });
        return o1;
    }(conglomerateObj, objIn2));
};


// 'Common' RequireJS config properties object. Both config objects use these values.
var reqCommon = {
    baseUrl: '../scripts',
    paths: {
        lodash: '../public/lodash/lodash',
        bootstrap: '../public/bootstrap/js/bootstrap.min'
    }
};

// RequireJS config properties object 1. Configures section run with it to use an
// older version of jQuery (1.11.3) loaded using a CDN, for use with Bootstrap.
var req1 = require.config(mergeObjs({
    context: 'version1',
    paths: { jquery: 'https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min' }
}, reqCommon));

// RequireJS config properties object 2. Configures section run with it to use a 
// newer version of jQuery. Used for almost everything except Bootstrap.
var req2 = require.config(mergeObjs({
    context: 'version2',
    paths: { jquery: '../public/jquery' } //new, local version of jQuery
}, reqCommon));


//
// 1st require'd block; runs with req1 RequireJS properties object used & thus 
// jQuery 1.11.3. Mainly for running Bootstrap.
//
req1(['lodash', 'jquery'], function(main, ta, _) {

    // This IIFE is intended to load the older jQuery version in regardless of the presence of jQuery v2.1.4
    (function($) {
        console.log('1st block 1st section jQuery version: ' + $.fn.jquery); 
          //--> shows 1.11.3 as version
        window.jQuery = this.jQuery = $; // needed - Bootstrap uses jQuery on the window object.

        //Load Bootstrap after jQuery 1.11.3 confirmed loaded
        req1(['bootstrap'], function(bootstrap) {
            console.log("1st block 2nd section: bootstrap loaded!");
            console.log("1st block 2nd section: jQuery version: " + $.fn.jquery); 
          //--> still shows 1.11.3, even though block 2 has usually run by now
        });

    }(jQuery.noConflict(true)));
});


//
// 2nd require'd block; runs with req2 RequireJS properties object used & thus 
// jQuery 2.1.4. For almost everything except Bootstrap.
//
req2(['main', 'testaddedjsfile', 'lodash', 'jquery'], function(main, ta, _) {
    //this IIFE keeps the newer jQuery version separated from the old version.
    (function($) {
        console.log('2nd block jQuery version: ' + $.fn.jquery);
          //--> shows 2.1.4 as version
    }(jQuery.noConflict(true)));
    // the bind helps ensure calls to $ don't inadvertently call window.$. which will be occupy.
});

The IIFEs in the 1st & 2nd require'd blocks at the bottom were essential to making this work.

Prior to adding the ability to merge objects (function mergeObjs) and the default object in my own file, my require config objects (req1 & req2) became repetitive and messy.

Bootstrap was included below to prove the concept: the specific Bootstrap template I used required an older version to jQuery to be present on the window object...while the rest of my code in the app used 2.1.4.

The above setup allowed both Bootstrap and my own code to run without problems, each block consistently using the appropriate versions of jQuery, with one caveat: the second block is not able to explicitly call window.$ (a poor idea anyway).

My apologies for the length - this was a surprisingly tricky problem.