how to handle requirejs conflicts - javascript

I have a javascript plugin which can be added in any website. I am using requirejs in my plugin. When it is added to a website, which already has requirejs, I am getting script errors and the plugin is not working. I cannot find any noconflict method for requirejs. Suggest a solution.
Uncaught Error: Mismatched anonymous define() module: function () { return io; }
http://requirejs.org/docs/errors.html#mismatch
Similar case: link

I suggest, use old style Javascript methods to determine if requireJS is already part of the environment; if so, make no mention of adding requireJS; if not, then add it to the environment in the usual fashion (perhaps using document.write to emit a html script tag to invoke requirejs

Related

Can't get $ to work using RequireJS and MooTools

I'm attempting to build a site using a combination of RequireJS and MooTools. It's my first time using both libraries. There is plenty of documentation for using RequireJS with jQuery but less for using it with MooTools. I've found only this really. But I'm having some trouble and much of it probably is a result of ignorance; still, perhaps you all can help.
At the moment, I'm just trying to test out basic functionality and understand how I would go about setting this up. Here is what I have tried:
In my site footer, I have this script tag:
<script src="assets/js/vendor/require.js" data-main="../app.js"></script>
This loads requirejs with the file app.js. Inside app.js I mainly deal with paths:
requirejs.config({
"baseUrl": "assets/js",
"paths": {
"mootools": "//ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools-yui-compressed"
}
});
// Load the main app module to start the app
requirejs(["main"]);
Finally, in main.js, I have (so far) the following:
define(["mootools"], function($) {
var a = $$('.menu'); // .menu is a nav menu in the DOM
console.log(a);
var b = $('.menu');
console.log(b);
});
So here, a works, but b causes an error: undefined is not a function. So there are a couple of questions embedded here. First, can someone tell me what the difference in meaning for $ and $$ with mootools? I gather from this tutorial, that both are used in mootools. Also, why is it that mootools is not mapped to $? As I understand it, with jQuery, this is how you would do this, see here for example.
I'm sure there are some basic confusions here, but please have mercy. I'm a newbie to these tools.
MooTools (as is) is not AMD-compliant. David Walsh is cool but he does not like or use RequireJS. The info in his post is well out of date and not practical any more. In fact, I believe none of the MooTools-core team likes AMD or uses it. Anyway, that's beside the point. jQuery now IS based around AMD so using it is easy. MooTools tried it 2 years ago - https://github.com/arian/mootools-core/tree/1.5amd - and gave up. 1.5 is still not out (hopefully next week, still no AMD).
Anyway
You cannot do this quite in that fashion by expecting the script to magically return $ where a module has not been defined.
There is another issue here which is with the fact that you are loading a remote script and that you leave the protocol to be determined automatically - which are sort of quirky things for RequireJS to handle in their own accord.
Two or three ways to handle it.
you can just define a local module, eg your own mootools.js
define([
'http://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools-yui-compressed.js'
], function(){
return window.$;
});
then use by requiring it:
require(['mootools'], function($){
$(document.body).adopt(new Element('div[html=hi]'));
});
eg. http://jsfiddle.net/dimitar/5zYnW/
however, mootools will export all sorts of globals anyway, so it's not really useful. you are better off using the requirejs shim config.
shim example
require.config({
paths: {
mootools: 'https://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools-yui-compressed'
},
shim: {
mootools: {
exports: '$'
}
}
});
// some code.
require(['mootools'], function(){
document.id('foo').adopt(new Element('div[html=hi]'));
});
eg: http://jsfiddle.net/dimitar/5zYnW/1/
old school
I find that it's easier to load MooTools before RequireJS and assume it's all global in all modules that I write - it makes more sense as there are too many global exports to catch. eg. Class, Element, Request etc etc.
eg. https://github.com/epitome-mvc/Epitome/blob/master/example/js/model-demo-require.js -s from my MooTools MVC framework Epitome.
Here's example module code via a UMD wrap - https://github.com/epitome-mvc/Epitome/blob/master/src/epitome-model.js - the only code that implicitly requires MooTools is the node.js code.

RequireJS - Loading AMD modules both inside a require flow and inline

Consider this:
<script src='global.js'></script>
<script src='require.js'></script>
<script>
require(['modular_foo'], function() {
//do stuff
});
...and in side global.js we have, among other things:
//global.js
$.getScript("modular_bar.js");
where both modular_foo and modular_bar are anonymously defined AMD modules. Using requireJS, loading something like the above would give you our favourite error, mismatched anonymous define() modules.
It's fine enough as to why that error occurs (read up on that page if you'd like to know), but the problem is, what if you can't get out of this situation?
I'm working in an established platform which is very gradually migrating to a RJS flow, for now there's no way out of using both inline legacy scripts (some of which have AMD checks to trigger define()) and our requireJS entry-point simultaneously.
In some cases I can simply place inline AMD-compatible scripts above loading the require.js library, but that doesn't work when you need to load other things (modular_bar.js) asynchronously depending on the DOM content. I could also just comment out all AMD checks from those files loading externally to RJS but that's preventing making them incompatible with ever being loaded in a modular flow.
Anyone out there had a similar experience? How do you blend your flows to overcome these sorts of conflicts?
I do not have experience using this solution in a production environment but I spent a couple days on this question figuring out the best way to approach it.
You can use a modified RequireJS library that does not allow the anonymous define's to execute, if it is being passed through eval. Also, you can disallow any define calls by removing type check for string on name in the snippet below.
The following snippet is a modification to RequireJS that will ignore anonymous defines if being called by eval. You can find the fully modified require.js in this GitHub Gist.
The code relies on the parse-stack library. If you can't include the library before RequireJS, I suggest just concatenating it to the top of of the file.
Demo
// This is a snippet of RequireJS
// ...
define = function (name, deps, callback) {
var node, context;
// We will allow named modules to be defined by `eval`
if (!(typeof name == 'string' || name instanceof String))
{
var stack = parseStack(new Error());
// If we find any eval in the stack, do not define the module
// This is to avoid the "Mismatched anonymous define() module" error
// Caused by executing an anonymous define without requireJS
for(var i = 0; i < stack.length; i++)
{
if(stack[i].name == "eval")
{
return;
}
}
}
// ...

RequireJS: Difference between "requirejs" and "require" functions

I am using requireJS 2.x. I found out that some tutorials (and the official docs) sometimes use
requirejs.config({ [...] });
requirejs(["module"]) ...
and sometimes
require.config({ [...] });
require(["module"]) ...
Is there any difference between those two functions (require and requirejs)? I could not find any word about that in the docs. :(
They are exactly the same.
The reason is some environments might already have a require, in which case RequireJS doesn't overwrite it and allows usage of the library through requirejs
See this commit - https://github.com/jrburke/requirejs/commit/be45948433b053921dc6a6a57bf06d04e13b3b39
Are requirejs And require the Same?
As of RequireJS 2.1.15, require and requirejs in the global space are indeed "exactly the same", as can be evidenced by this test you can perform in the console:
> require === requirejs
true
That the test returns true tells you they are the exact same function object. They are not two functions that happen to have similar or identical code. They are the same object, period.
Note, however when you execute define(['require'], function (require) { The require passed to the function is normally different from the global require.
Should You Use require or requirejs?
It depends. RequireJS is an AMD loader but it is not the only loader in town. If you want to write code that conforms 100% to the AMD spec, so that someone using your code can use whatever loader they want without having to modify your code, then you should use require at the global level, because requirejs is specific to RequireJS. Another AMD loader won't define it. The AMD spec defines require but not requirejs.
If you are loading something else that defines a global require then you have to use requirejs at the global level to avoid conflict.
Inside a module, always use define to obtain a reference to require. You should do this quite irrespective of whether there is a conflict in the global space.
OK, they may indeed be "exactly the same". Let's then focus on why you would use one versus the other...
What is unclear is what should be considered "best practice": If requirejs provides extra assurance "if some environments might already have a require", then wouldn't it be a good idea to always use the requirejs function to define a require configuration rather than the require function?
Also, what happens if the unthinkable happens and the environment in question not only already has a "require" defined but also has a "requirejs" defined? Does that mean we should have a requirejsjs too? And so on...?
They are Same
Open website which loaded require already
then open Chrome console
type require in console and press enter
type requirejs in console and press enter
you can find that they are same function with different names

How to embed/import jQuery into another JavaScript library without causing potential clashes with jQuery/others deployed on the website?

I am working on a JavaScript library that makes internal use of jQuery. However, when the time comes for its deployment, I would prefer to simplify things (w.r.t. deployment) and not worry about whether the environment has (or doesn't have) jQuery already included in <head>.
I should mention that my library is implemented as a class in Coffescript and the resulting .js file has the default function wrapper to isolate scope.
I can think of a few solutions to this problem:
Ask the website admin whether they have jQuery already present. If
yes, just include the library itself. If not, then include jQuery +
the library, perhaps in a single file and concatenated. Deployment is harder, but problem is likely solved.
Create a file that concatenates jQuery and my lib code and always
have the website admins just include this file. To prevent clashes,
do a var myJ = jQuery.noConflict() right after the jQuery code.
Do as in (2) above, but call the var myJ = jQuery.noConflict() inside the encapsulated Coffeescript class.
In summary, the objectives for this challenge are:
Absolutely avoid any breakage on the deployed website, regardless of
what they might be using
Keep deployment as simple as possible
Avoid unnecessary transfer of jQuery, if possible
My concerns are:
What if the site already has jQuery, but needs an older/newer
version?
What if my noConflict() call breaks something on their
end?
What is the best way to tackle this situation? Am I missing something?
CoffeeScript has a -b option to compile without the top-level function wrapper. Using this method, you could use your own top-level function wrapper instead.
i.e.
(($) ->
# ...
# your code
# ...
)(jQuery.noConflict())
Then, as part of your build process, concatenate jQuery onto the front of the compiled output. The appropriate Linux/Mac shell command would be:
(cat jQuery.js; coffee -pb yourSource.coffee) > yourCompiledFileWithjQuery.js
The p option for CoffeeScript prints the compiled output to stdout, so that you can combine it with the cat jQuery.js and redirect that output into yourCompiledFileWithjQuery.js
This would ensure that, immediately before your code is executed, jQuery would be included. jQuery keeps a reference to the old owner of $, so if some library or another version of jQuery is already using it it will be returned to them with the jQuery.noConflict() call.
jQuery.noConflict() also returns a reference to that jQuery, so that is how it would be passed to the $ of your code.
I hope that's clear.
Extra:
As of CoffeeScript 1.3, released a few days ago, you could use this instead for your top-level function wrapper, which is somewhat clearer:
do ($ = jQuery.noConflict()) ->
# ...
# your code
# ...
If your end script as a closure you can simply pass it jQuery as an argument and check if that is undefined or not.
(function($) {
if (!$) {
// load jQuery
} else {
// check jQuery version if needed or just use jQuery
if ($.fn.jquery !== '1.7.2') {
// load 1.7.2
};
};
})(window.jQuery || false);
Must use window.jQuery as jQuery only will generate an error if jQuery is not declared

Curl throwing ‘Promise already completed’ error

I’m currently testing various asynchronous-resource-loaders to see which one I want to use. At the moment Curl is throwing a ‘Promise already completed’ error…and their documentation says ‘this should never happen’.
I “suspect” I must to use a ‘define’ within each file being loaded (hope not). Further, their documentation says Curl can work with non-AMD javascript files. But...I am new to AMD and since Curl is far-faster than the other ones I'm testing...I am willing to put some time into understanding this better.
Lastly...
Even though FireBug shows the errors...all the files STILL LOAD asynchronously! But, BECAUSE there are errors...the 'then' portion of the code never gets called.
So My Questions Are:
Do I have to update all the JavaScript file-objects to be contained in a 'define'? (...hope not)
Can you see any other problem syntactically?
The Head’s Code Looks Like This:
<script type="text/javascript">
///<summary>Configuration</summary>
curl = { baseUrl: 'Includes/JavaScript/' };
</script>
<script src="Loaders/Curl/curl.js" type="text/javascript"></script>
<script type="text/javascript">
function onSuccess() {
}
function onError(ex) {
//alert(ex);
}
require(["MooTools/Core/mootools-1.2.2-core-jm",
"MooTools/mGeneral",
"jQuery/Core/jquery-1.3.2",
"jQuery/Core/jquery.tools.min",
"jQuery/ThirdPartyPlugIns/jquery.tmpl"])
.then(onSuccess, onError);
//require(["jQuery/TopUp/top_up-min"], null);
require(["jQuery/ThirdPartyPlugIns/jquery.dimensions",
"jQuery/ThirdPartyPlugIns/jQuery.Color.Animations",
"jQuery/ThirdPartyPlugIns/jquery.corners.min",
"jQuery/ThirdPartyPlugIns/jquery.tipsy",
"jQuery/ThirdPartyPlugIns/jquery.numberformatter-1.1.0",
"jQuery/ThirdPartyPlugIns/jquery.tipsy"]);
require(["general",
"WindowCenter",
"ThirdPartyPlugin/KeyBoardCapture",
"ThirdPartyPlugin/bsn.AutoSuggest_2.1.3",
"ee/8Ball",
"ee/EE"]);
</script>
Again...I'm sure it is caused by inexperience with AMD-styled code, but I still need help...so any is appreciated.
Typically, you should wrap your modules in a define() or append a define() at the end of the file if those modules have no dependencies. It seems, though, that those modules all depend on jQuery, if not other modules/files.
Since you're not using standard AMD require()/define() protocol, AMD is not really helping you with these modules. Unless you plan to write your own modules using define(), then you could use just about any async loader.
That said, there is a way to make curl.js work with non-AMD modules/files. Use the js! plugin. Here's your first block of files translated to use the js! plugin (note I also added the ".js" ext back on which I like to do with non-modules):
// we load the core files first, then get the next block that depends on them
curl([
"js!MooTools/Core/mootools-1.2.2-core-jm.js",
"js!jQuery/Core/jquery-1.3.2.js"
]).next([
"js!MooTools/mGeneral.js",
"js!jQuery/Core/jquery.tools.min.js",
"js!jQuery/ThirdPartyPlugIns/jquery.tmpl.js"
]).then(onSuccess, onError);
If any of those files within each array depend on each other, you can also use the !order suffix on them to ensure they wait for other files before executing/evaluating (be sure you're setting proper cache headers, though). Actually, the !order suffix is the fastest method as long as there are no caching issues (mobile browsers add some additional constraints on file size).
Were there any other error messages? Specifically, I would expect curl.js to throw at least one error besides just "Promise not completed".
Also, please check the Net tab (Firebug) or the Network tab (Chrome) to check that curl.js is looking in the correct location for the modules.
FWIW, I am planning to remove the alias require --> curl. The reason is that the global require function is non-standard (and explicitly not standardized in the AMD proposal). I suggest you use curl() instead of require().
curl.js also allows it's top-level api to be aliased explicitly via the "apiName" config param if you really, really want to use the name "require". :)
<script>curl = { apiName: "require" }; </script>
<script src="path/to/curl.js"></script>
<script>require(["some/modules"]).then(success, failure);</script>
More FWIW: the standard require is typically only needed in a module and can be requested by including it as a dependency:
define(["require"], function (require) {
require(["another/module"], function (another) {
// use another module here
});
});
-- John
If you're only doing normal javascript file loading (not modules), as it appears, i would encourage you to check out LABjs (http://labjs.com). LABjs focuses on being the most performance optimized loading solution (to the exclusion of some other features like module/dependency style stuff).
In fact, LABjs 2.0a (https://github.com/getify/LABjs/blob/master/next/LAB.src.js), which will be fully released in the next few days, is really exceptionally fast (even more than 1.2) at loading general scripts in parallel. I encourage you to give it a try, unless (as John eludes to above) you plan to go to module syntax... then stick with Curl or RequireJS.

Categories