requirejs export global variable - javascript

I am trying to use bootbox (http://bootboxjs.com) with requirejs.
main.html
<script>
var require = {
baseUrl: 'js',
paths: {
"jquery" :['jquery-1.11.0.min'],
"bootbox" :['bootbox.min'],
"bootstrap" :['//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min']
},
shim:
'bootstrap' :{deps:['jquery']},
'bootbox' :{deps:['bootstrap'],exports: 'bootbox'}
}
}
</script>
<script src="require.min.js"></script>
<script src="myscript1.js"></script>
main.js
define(['bootbox'],function(bootbox){
bootbox.alert("Hello world!"); // working properly
});
myscript1.js
require(['main'],function(){
bootbox.alert("Hello world!"); // not functioning (bootbox is not defined)
});
Normally once bootbox plugin is loaded, we can use bootbox anywhere on the page with this: bootbox.alert("Hello world!"); When using requirejs, I have to pass the bootbox variable and define it everytime when using requirejs in order to use bootbox. I have tried with "exports", but it doesn't seem help.
How can we have the bootbox variable available globally once it is loaded?
Thank you.

Here's the deal. Bootbox detects whether it is running in an AMD loader in place (like RequireJS). If so, it won't export anything into the global space but will instead define itself as an AMD module, to be loaded by an AMD loader.
Tidoo's suggestion of loading Bootbox with a script tag works, if you do it carefully. You'd have to load Bootbox before you load RequireJS, for one thing. Otherwise, it would detect that RequireJS is loaded, determine that it is running with an AMD loader, and define itself as an AMD module. This would cause a mismatched anonymous module error from RequireJS. Another thing is that you'd have to load jQuery outside RequireJS and load it before Bootbox. So that's another script tag.
I'd suggest avoiding that solution by simply modifying your code to add the required dependency:
require(['bootbox', 'main'],function(bootbox){
bootbox.alert("Hello world!");
});
Also, you must not use a shim configuration for Bootbox because it detects whether there is an AMD loader around and calls define by itself if it detects one. A shim configuration is needed only for code that does not call define.

If you want Bootbox to be available globally you should include it manually with a script tag. RequireJS doesn't expose it.
However, I highly recommend against this. The whole idea of dependency frameworks such as RequireJS is that you don't define anything on global scope, but to make your dependencies explicit. This not only allows you to lazy load scripts, but it also makes it possible to later replace dependencies, e.g. for unit testing.
EDIT:
As Louis correctly mentioned Bootbox already has AMD support. If it detects RequireJS (or any other AMD loader) it doesn't expose anything to the global scope, but since it has AMD support you also don't need to shim it.

Related

Error: Mismatched anonymous define() module when trying to get jQuery maks plugin to work [duplicate]

I'm getting this error when I browse my webapp for the first time (usually in a browser with disabled cache).
Error: Mismatched anonymous define() module: function (require) {
HTML:
<html>
.
.
.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script> var require = { urlArgs: "v=0.4.1.32" }; </script>
<script data-main="assets/js/main" src="assets/js/libs/require.js"></script>
<script src="assets/js/ace/ace.js?v=0.4.1.32"></script>
</body>
</html>
JS:
$(function () {
define(function (require) {
// do something
});
});
Anyone know exactly what this error means and why its happening?
source file, a short discussion about it in the github issues page
Like AlienWebguy said, per the docs, require.js can blow up if
You have an anonymous define ("modules that call define() with no string ID") in its own script tag (I assume actually they mean anywhere in global scope)
You have modules that have conflicting names
You use loader plugins or anonymous modules but don't use require.js's optimizer to bundle them
I had this problem while including bundles built with browserify alongside require.js modules. The solution was to either:
A. load the non-require.js standalone bundles in script tags before require.js is loaded, or
B. load them using require.js (instead of a script tag)
In getting started with require.js I ran into the issue and as a beginner the docs may as well been written in greek.
The issue I ran into was that most of the beginner examples use "anonymous defines" when you should be using a "string id".
anonymous defines
define(function() {
return { helloWorld: function() { console.log('hello world!') } };
})
define(function() {
return { helloWorld2: function() { console.log('hello world again!') } };
})
define with string id
define('moduleOne',function() {
return { helloWorld: function() { console.log('hello world!') } };
})
define('moduleTwo', function() {
return { helloWorld2: function() { console.log('hello world again!') } };
})
When you use define with a string id then you will avoid this error when you try to use the modules like so:
require([ "moduleOne", "moduleTwo" ], function(moduleOne, moduleTwo) {
moduleOne.helloWorld();
moduleTwo.helloWorld2();
});
I had this error because I included the requirejs file along with other librairies included directly in a script tag. Those librairies (like lodash) used a define function that was conflicting with require's define. The requirejs file was loading asynchronously so I suspect that the require's define was defined after the other libraries define, hence the conflict.
To get rid of the error, include all your other js files by using requirejs.
Per the docs:
If you manually code a script tag in HTML to load a script with an
anonymous define() call, this error can occur.
Also seen if you
manually code a script tag in HTML to load a script that has a few
named modules, but then try to load an anonymous module that ends up
having the same name as one of the named modules in the script loaded
by the manually coded script tag.
Finally, if you use the loader
plugins or anonymous modules (modules that call define() with no
string ID) but do not use the RequireJS optimizer to combine files
together, this error can occur. The optimizer knows how to name
anonymous modules correctly so that they can be combined with other
modules in an optimized file.
To avoid the error:
Be sure to load all scripts that call define() via the RequireJS API.
Do not manually code script tags in HTML to load scripts that have
define() calls in them.
If you manually code an HTML script tag, be
sure it only includes named modules, and that an anonymous module that
will have the same name as one of the modules in that file is not
loaded.
If the problem is the use of loader plugins or anonymous
modules but the RequireJS optimizer is not used for file bundling, use
the RequireJS optimizer.
The existing answers explain the problem well but if including your script files using or before requireJS is not an easy option due to legacy code a slightly hacky workaround is to remove require from the window scope before your script tag and then reinstate it afterwords. In our project this is wrapped behind a server-side function call but effectively the browser sees the following:
<script>
window.__define = window.define;
window.__require = window.require;
window.define = undefined;
window.require = undefined;
</script>
<script src="your-script-file.js"></script>
<script>
window.define = window.__define;
window.require = window.__require;
window.__define = undefined;
window.__require = undefined;
</script>
Not the neatest but seems to work and has saved a lot of refractoring.
Be aware that some browser extensions can add code to the pages.
In my case I had an "Emmet in all textareas" plugin that messed up with my requireJs.
Make sure that no extra code is beign added to your document by inspecting it in the browser.
Or you can use this approach.
Add require.js in your code base
then load your script through that code
<script data-main="js/app.js" src="js/require.js"></script>
What it will do it will load your script after loading require.js.
I was also seeing the same error on browser console for a project based out of require.js. As stated under MISMATCHED ANONYMOUS DEFINE() MODULES at https://requirejs.org/docs/errors.html, this error has multiple causes, the interesting one in my case being: If the problem is the use of loader plugins or anonymous modules but the RequireJS optimizer is not used for file bundling, use the RequireJS optimizer. As it turns out, Google Closure compiler was getting used to merge/minify the Javascript code during build. Solution was to remove the Google closure compiler, and instead use require.js's optimizer (r.js) to merge the js files.

jQuery noconflict, bootstrap and requirejs

The environment I'm developing in is using jQuery 1.7.1 while I need to use specifically jQuery 2.1.3. But when I do use 2.1.3 some legacy code breaks (as its using 1.7.1) so I had to use jQuery.noconflict on 2.1.3
jquery-private.js:
define(["jquery"], function(jQuery){
return jQuery.noConflict(true);
});
so then inside my requirejs config file I have this:
config.js:
requirejs.config({
baseUrl: '../',
paths: {
'jquery': 'js/jquery/jquery',
'jqueryui': 'js/jquery-ui/jquery-ui',
'bootstrap': 'js/bootstrap',
},
map: {
// '*' means all modules will get 'jquery-private'
// for their 'jquery' dependency.
'*': {
'jquery': 'jquery-private'
},
// 'jquery-private' wants the real jQuery module
// though. If this line was not here, there would
// be an unresolvable cyclic dependency.
'jquery-private': {
'jquery': 'jquery'
}
},
shim: {
'bootstrap': {
deps: ['jquery']
}
}
});
so then when I require bootstrap
widget.js:
require([
"jquery",
"bootstrap"
], function(jqr){
// SOME CODE
});
I get an error:
Uncaught Error: Bootstrap's JavaScript requires jQuery version 1.9.1 or higher
So bootstrap is picking up 1.7.1.
How can I make it pickup 2.1.3 without making changes to bootstrap.js file?
Why it is failing?
Your current attempt cannot work because your jquery-private setup ensures that as soon as jQuery is loaded as a RequireJS module, noConflict() is called. So long as the code loaded with RequireJS is referring to jQuery through a define call (e.g. define(['jquery'], function ($) {) there is no problem. However, any code that is shimmed will refer to the $ or jQuery globals and thus will refer version 1.7.1.
A Solution
Absent any other constraints, the preferred solution is to have the entire code base use the same jQuery version. Upgrade 1.7.1 to the latest in the 1.x series, and use that. According to the download page, there is no API difference between 2.x and a relatively recent release in the 1.x series (I would say 1.9.x and later). Of course, this means that the code that depended on 1.7.1 may have to be updated to work with the latest jQuery in the 1.x series.
I would have suggested upgrading to the 2.x series but you mention in comments needing compatibility with IE 6 and 7. Note here: if you do manage to get 1.7.1 and 2.1.3 to load for the same page, that part of the code that uses 2.1.3 wont' be compatible with IE 6 and 7 so the page is effectively no longer compatible with IE 6 and 7.
To use this solution, besides the changes that must be done for the upgrade, you must:
Make sure that jQuery loads before RequireJS. Otherwise, it will detect RequireJS and call define but then it won't be reliably available to code that is not loaded with RequireJS. (I said it won't be "reliably available" because although once the jquery module is loaded, then the jQuery and $ globals will exist, the problem is that code that is not loaded with RequireJS cannot wait for RequireJS to load jQuery. So, unless you take pains to write your own synchronization code, it won't work reliably.)
Create a RequireJS module which merely makes the jQuery loaded before RequireJS available to RequireJS modules as a module, so:
define('jquery', function () { return jQuery; });
This could be placed just before your call to require.config. This creates a "fake" jquery module which merely returns the global jQuery symbol. (It could just as well return $.)
Alternatives?
I do not see a robust alternative to the solution above. It is not that difficult to come up with a proof of concept that would demonstrate another approach. However, it would fail as soon as you try to use it on a real project. The problem is that RequireJS is inherently asynchronous, so you cannot start messing with the $ and jQuery globals to set them the way you want and be sure that everything you want to happen will happen at the time you want it to happen. Moreover, any code loaded before RequireJS that happens to initiate asynchronous operations that could happen interleaved with RequireJS' module loading would throw a monkey wrench into the whole operation. I'd rather refrain from proposing solutions that will fail as soon as they go from proof of concept to real world applications.

How can I load non-AMD dependencies in the defined order with dojo?

I try to make a non-AMD library loadable with dojo, I've chosen a separate folder as a new (pseudo) AMD-package and placed the files of that library in that folder, together with the main.js file, which will get loaded by convention by the dojo loader when the package is requested. In this main.js file I simply put the names of my library files in the dependency list of the define() call.
define([
"jquery",
"./lib/jquery-ui/jquery-ui.min",
"./the.actual.library.that.uses.the.others",
], function () {
return window.someGlobalSetByTheLibrary;
});
The problem with this is: the loading order of that dependencies depends on the network latency, it is not guaranteed to be the order they appear in the define().
That causes (sometimes) an error because the actual library file needs its own dependencies to be loaded first.
Dojo has a perfect means to help yourself: loader plugins.
You can write your own sequential loading plugin that ensures the loading order for you.
(For copyright reasons of corporate owned code I can not post the implementation here, but it's quite easy using dojo's Deferred and Promise to chain one loading request after the other, internally using require() to do the actual loading).
Let's assume, your dojo loader plugin has the module id myPackage/sequentialLoading.
Then, your main.js will look like this.
define([
"myPackage/sequentialLoading!jquery",
"myPackage/sequentialLoading!./lib/jquery-ui/jquery-ui.min",
"myPackage/sequentialLoading!./the.actual.library.that.uses.the.others",
], function () {
return window.someGlobalSetByTheLibrary;
});

Loading jQuery plugins using RequireJS -- jQuery undefined intermittently even after specifying deps?

I am attempting to load jQuery.jstree through RequireJS. You can see the exact source of the plugin here: https://gist.github.com/MeoMix/7882144
As I understand it, jQuery.jstree has three dependecies: jQuery, jQuery UI, and jQuery.cookie.
I begin with by loading my RequireJS shim config and then call an initial 'require' to kick things off:
require.config({
// Set the base URL to the Scripts directory of CSWeb
baseUrl: '/csweb/Scripts/',
shim: {
'jquery-ui': ['jquery'],
'jquery.jstree': ['jquery', 'jquery-ui', 'jquery.cookie'],
'jquery.cookie': ['jquery']
}
});
Here, I define my base URL relative to the root of my JavaScript files. The file jquery.js is located at the baseUrl. I also define dependencies for both plugins. Note: I have tried playing around with more explicit shim declarations including defining exports. I noticed no difference in effect.
After defining my config, I call:
require([
'jquery',
'jquery-ui',
'jquery.cookie',
'jstree/jquery.jstree'
], function () {
'use strict';
});
Doing so yields an error intermittently. Clearly an async-loading issue. The error reads:
Uncaught ReferenceError: jQuery is not defined jquery.jstree.js:978
Line 978 of jquery.jstree is simply where jQuery is passed into the closure to begin initialization of the plugin:
// 978 jquery.jstree.js: })(jQuery);
What am I not understanding here? I don't seem to experience this issue with most of my plugins. Is there something especially crappy about how this jstree plugin was written such that it is giving RequireJS fits? Or am I not understanding a core mechanic of RequireJS shim configuration?
UPDATE 1: It appears that it is something to do with the fact that I load jquery.jstree from a path. If I load another, empty file (jstree/jquery.test) -- I am able to replace the issue. However, if I then move test up a directory such that it is level with the other plugins -- it all loads fine.
The whole path you give to the shim configuration has to match the whole path of the module you require.
You name the shim jquery.jstree but you require it as jstree/jquery.jstree, so RequireJS does not use the shim and thus does not know that the plugin depends on jquery, etc. and so you get intermittent errors.
For things like plugins that I might want to use globally, I prefer to give them a well-known name that I can use throughout my application without worrying about paths. So in your case, I'd fix the problem by adding this to my config:
paths: {
"jquery.jstree": "jstree/jquery.jstree"
}
and I would then require it jquery.jstree.

Loading jQuery, Underscore and Backbone using RequireJS 2.0.1 and shim

I am experimenting a little bit with RequireJS 2.0.1. My goal is to load correctly jQuery, Underscore and Backbone. From the original RequireJS doc I discovered that the author J. Burke added (to this new release) a new config option called shim.
Then I wrote this stuff down here:
index.html
<!DOCTYPE html>
<html>
<head>
<title>Testing time</title>
<script data-main="scripts/main" src="scripts/require.js"></script>
</head>
<body>
<h1>Testing time</h1>
</body>
</html>
scripts/main.js
requirejs.config({
shim: {
'libs/jquery': {
exports: '$'
},
'libs/underscore': {
exports: '_'
},
'libs/backbone': {
deps: ['libs/underscore', 'libs/jquery'],
exports: 'Backbone'
}
}
});
define(
['libs/jquery', 'libs/underscore', 'libs/backbone'],
function (jQueryLocal, underscoreLocal, backboneLocal) {
console.log('local', jQueryLocal);
console.log('local', underscoreLocal);
console.log('local', backboneLocal);
console.log('global', $);
console.log('global', _);
console.log('global', Backbone);
}
);
Everything seems to work quite fine, but I have the feeling that I'm missing something, I know that there are AMDed version of jQuery and Underscore but if the setup is so simple I don't understand why I should use them.
So, is this setup right or I'm missing something?
You only need to use "shim" config if the library does not already call define() to declare a module. jQuery does this already, so you can remove that from the shim config. The above code will work as is, but the exports shim config for jQuery will be ignored since jQuery will call define() before the shim work is done.
The downsides with the shim vs having the script call define() to define a module:
It is less portable/reliable: every developer needs to do the shim config, and keep track of library changes. If the library author does it inline in the library, everyone gets the benefits more efficiently. The code templates at umdjs/umd can help with that code change.
Less optimal code loading: shim config works by loading shim deps before loading the actual library. So it is a bit more sequential loading than parallel. It is faster if all scripts can be loaded in parallel, which is possible when define() is used. If you do a build/optimization for final deployment and combine all the scripts into one script, then this is not really a downside.
What you are doing is correct, but jQuery does not need to be in the shim config because it exports an AMD (Asynchronous Module Definition) module. Underscore removed its support for AMD / Require.js quickly after adding it, see: Why underscore.js removed support for AMD
Shim is intended as a convenience for using libraries that do not export an AMD module. If the library you are using does support AMD, or has 2 versions (one that supports AMD, and one that is a global variable) you should use the AMD version. You should use the AMD version for the same reasons you would use AMD in the first place and also because the library may include require.js (or Almond ) in its source and would be adding unnecessary file size to your project.
Can you actually avoid "shimming" jquery in the original example (where the path to jquery is set to 'libs/jquery'), since jquery adds the name "jquery" in their amd module definition?
define( "jquery", [], function () { return jQuery; } );
My experience is that you need to put jquery.js in the baseurl directory to get the jquery amd module defined as expected, or "shim" it like in the original example.

Categories

Resources