RequireJS module attempts to load shim'ed module - requirejs

I'm having an issue attempting to create a RequireJS shim for some javascript code that was written by another team in my organization. The script is loaded via a noraml HTML script as such:
<script src="MyCustomModule.js" type="text/javascript"></script>
My main.js contains the following:
requirejs.config({
paths: { 'text': 'durandal/amd/text' },
shim: {
'MyCustomModule': { exports: 'My.Custom.Module' }
}
});
And I have tried accessing the custom module in a variety of ways, but this is my current code:
define(['MyCustomModule'], function (require, MyCustomModule) {
...
}
But each time the page/app loads I get an error from RequireJS indicating that it failed to load app/MyCustomModule.js (and I can see the 404 error in the console where it attempted to request the file from the server). What am I doing wrong?

You also need to include MyCustomModule in paths:
requirejs.config({
paths: {
'text': 'durandal/amd/text'
'MyCustomModule': 'path/to/MyCustomModule'
},
shim: {
'MyCustomModule': {
exports: 'My.Custom.Module'
}
}
});
If you don't do that, define(['MyCustomModule'] (...) will look for the dependency in the baseUrl location, in your case: app/MyCustomModule.
In other words: shim can't "pick up" global variables that are not loaded by RequireJS.

Related

How to get a single javascript page using r.js

I am doing my first try using requireJS and it works great !
I now would like to use the optimizer and i meet some issues when running my code in the browser.
I have these JS files:
/public/javascripts/build.js
/public/javascripts/main.js
/public/javascripts/lib/jquery.min.js
/public/javascripts/lib/require.min.js
/public/javascripts/a.js
/public/javascripts/b.js
/public/javascripts/c.js
a.js, b.js and c.js are modules i define for my application using requireJS.
main.js:
require.config({
paths: {
'jQuery': 'lib/jquery.min.js'
},
shim: {
'jQuery': {
exports: '$'
}
}
});
require(['a.js'], function(A){
var Entity = new A();
});
build.js
({
baseUrl: ".",
paths: {
requireLib: "lib/require.min",
jquery: "lib/jquery.min"
},
name: "main",
out: "main-built.js",
include: ["requireLib"]
})
Also i am wondering why do we have to specify the paths of the libraries into the build.js and not the other javascript files.
When i do not use the optimizer and only load the file
<script src="/javascripts/lib/require.min.js" data-main="/javascripts/main"></script>
it works great, but when i run r.js -o ./public/javascripts/build.js and only load
<script src="/javascripts/main-built.js"></script> i get the error Uncaught TypeError: undefined is not a function in the minified code.
How to explain that ?
Here are the logs i get when running r.js
Tracing dependencies for: main
Uglifying file: /public/javascripts/main-built.js
/public/javascripts/main-built.js
----------------
/public/javascripts/lib/require.min.js
/public/javascripts/a.js
/public/javascripts/b.js
/public/javascripts/lib/jquery.min.js
/public/javascripts/c.js
/public/javascripts/main.js
This is definitely wrong:
require(['a.js'], function(A){
var Entity = new A();
});
You should not use extensions in the list of dependencies you give to require or define. Modules should be named without extension. So here 'a', not 'a.js'. Using 'a.js' will cause RequireJS to fail loading what you really want once the optimizer has run. Let's say you have a file named a.js which has:
define(function () {
return function () {};
});
The optimizer will include it into your main-built.js file like this:
define("a", function () {
return function () {};
});
Note how the first parameter to define is now "a". This has been added by r.js. This is the name of the module. When you load main-built.js, a module named "a" is defined. When you use require with "a.js", you are telling RequireJS you want something in a file named a.js so RequireJS will go looking for that and ignore what is in main-built.js.
Also, jQuery 1.8 or over does not need a shim.
I just have added
shim: {
'jQuery': {
exports: '$'
}
}
into the build.js file, and it works perfectly !
Thanks !

Why is requirejs trying to load .map?

I am trying to load scripts from a CDN (cdnjs to be specific), and in requirejs you have to leave the extension off like so:
require.config({
baseUrl: '/static/js/',
paths: {
underscore: ['//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.1/underscore-min']
},
shim: {
'underscore': {
exports: '_'
}
}
});
But when I do this, the browser tries to load underscore-min.map and not underscore-min.js.
How do I fix this, and also what is a .map?
.map files are needed for sourceMap support in the browser. This is the last line from the file you load from the CDN:
//# sourceMappingURL=underscore-min.map
This line makes your browser to load the .map file.

require js shim not working for this code

I have the following code.
<script src="js/libs/require.js"></script>
<script>
requirejs.config({
baseUrl:'js/modules/',
paths:{
'bbn':'../libs/backbone',
'underscore':'../libs/underscore'
},
shim:{
'bbn':{
exports:'B',
deps:['underscore']
}
}
})
requirejs(['bbn'], function(B){
console.log(B)
});
</script>
The function parameter B is not pointing to Backbone. Instead its getting logged as undefined.
I followed the following post and arrived to this point:
Loading Highcharts via shim using RequireJS and maintaining jQuery dependency
I see both underscore and backbone JavaScript files getting downloaded in firebug.
Underscore is not AMD compat either, so make sure you shim that too:
requirejs.config({
baseUrl:'js/modules/',
paths:{
'bbn':'../libs/backbone',
'underscore':'../libs/underscore'
},
shim:{
'bbn':{
exports:'Backbone',
deps:['underscore']
},
'underscore': {
exports: '_'
}
}
})
requirejs(['bbn'], function(Backbone){
console.log(Backbone)
});
You will see Underscore being downloaded but because it not defined as a proper module RequireJS just treats it as a normal JS file and doesn't get a return value
The latest version of Underscore (~1.6.0 as of writing this) is AMD-compatible. Do not use it as a shim or you may run into issues.

How to define a module that is different from its filename?

I am running into a strange error. EDIT Happens in Firefox, but not Chrome
In my HTML page I have this:
<script type="text/javascript">
require(['blah']);
</script>
In a javascript file named someFileNameNotNamedBlah.js I have this:
define(
'blah',
['jquery', 'amplify', 'config' ],
function ($, amplify, config) {
...
});
The browser seems to be looking for blah.js... Why? How do I fix this?
Firebug looking for a filename that is not there
The question you need to ask yourself is this: Given that RequireJS loads modules asynchronously via a XHR request, how could it know to look for the module blah in a file called someFileNameNotNamedBlah.js unless it's told where it lives?
You should define an alias for the module in your paths configuration:
require.config({
paths: {
blah: 'someFileNameNotNamedBlah'
}
});
You can then remove the module name from your module:
define(['jquery', 'amplify', 'config' ], function ($, amplify, config) {
//...
});
And find it by the alias:
require(['blah']);

Correct way of loading non-AMD compatible jQuery plugins in require.js with jQuery in noConflict mode?

Say I want to use jquery together with a standard, non-amd enabled jquery plugin that has been defined using standard closure: (function($))( $.fn.myplugin = { ... } )(jQuery); and it all sits inside of a js/libs/jquery/jquery.myplugin.js.
I use this config:
require.config({
baseUrl: 'js/',
paths: {
'jquery': 'libs/jquery/jquery-noconflict',
'underscore': 'libs/underscore/underscore',
'backbone': 'libs/backbone/backbone',
'jquery-myplugin': 'libs/jquery/jquery.myplugin'
},
shim: {
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'jquery-myplugin': {
deps: ['jquery']
}
});
I load jQuery in no-conflict mode in libs/jquery/jquery-noconflict.js, becase I don't want to pollute global namespace:
define(['libs/jquery'], function () {
return jQuery.noConflict(true);
});
and this is how I load my main app.js:
define([
'jquery',
'underscore',
'backbone',
'jquery-myplugin'],
function($, _, Backbone, MyPlugin){
//MyPlugin is always undefined, not even sure if
//I should be passing it here if it only extends jQuery?
});
Now, here is the problem I am experiencing - while I can use all libraries defined above without any problems, I could not work out the correct shim configuration to load non-AMD enabled jquery plugins.
I've tried setting up jquery-myplugin as deps of the jquery (and other way around) but I could never get it working.
It seems like I'm having problem with the following scenario:
jQuery loads in no-conflict mode.
plugin code runs, extending the instance of the jQuery above
I can use $ within my application, extended by the plugin code, so $.myplugin is available.
I have seen similar questions floating around but none of them actually resolves this issue giving only vague suggestions such as "use shim config"...
Edit
I also tried using
"jquery-myplugin": {
deps: ["jquery"],
exports: "jQuery.fn.myplugin"
}
And whilst plugin methods are available once loaded as AMD module this way, I still can't access: $('.class').myplugin() as default $ object hasn't been extended with myplugin code.
Using jQuery.noConflict(true) removes the jQuery global variable. When your plugin loads, it tries to access jQuery, but can't, causing this failure.
If your plugin was a module, it could get access to jQuery as a dependency. Or you could leave jQuery available as a global.
First, insure that "path/to/jquery-myplugin" actually extends window.jQuery and not $
noConflict() leaves window.jQuery object defined but unbinds itself from window.$ On some new browsers window.$ is built in alias for native document.querySelectorAll function.
Second, your myplugin does NOT need to return itself, as it cannot be used by itself. Since it extends jQuery, return jQuery from myplugin call.
Lastly, "path/to/jquery-myplugin" is NOT a module. It's a plain JS file. It's possible RequireJS tries to load it like a module and does not find define() call, which leads to mess. Try actually adding ".js" file extension to the reference to signal to RequireJS that it needs to use "js!" plugin to load the resource.
require.config({
paths: {
"jquery": "path/to/jquery",
"jquery-myplugin": "path/to/jquery-myplugin.js"
},
shim: {
"jquery": {
init: function() {
return window.jQuery.noConflict();
},
"jquery-myplugin": {
deps: ['jquery']
init: function($) {
return $;
},
}
}
});
I had the same problem as you today. Here is how I could fix it :
requirejs.config({
"baseUrl": "js/lib",
"paths": {
"app": "../app"
}
});
// Final version of jQuery with all needed plugins.
define("jquery", ["jquery-core", "myplugin"], function(jqCore) {
return jqCore;
});
// Define core jQuery module.
define("jquery-core", ["jquery-1.9.1.min"], function() {
return jQuery.noConflict(true);
});
// This module exposes jquery module to the global scope and returns previous defined version.
define("jq-global", ["jquery-core"], function(jqCore) {
var tmp = jQuery;
jQuery = jqCore;
return tmp;
});
// Define your plugin here, and don't forget to reset previous jQuery version.
define("myplugin", ["jq-global", "jquery.myplugin"], function(jqGlobal, jqPlugin) {
jQuery = jqGlobal;
});
// Load the main app module to start the app
requirejs(["app/main"]);
Now in my app/main.js file I can do the following :
define(["jquery"], function($) {
$('body').myplugin();
});
The idea here is to expose jQuery temporary before plugin code is executed. So far I didn't test the solution in a larger environment with a lot more modules to load, so I can't guarantee it will work in the long term ;)
Edit
This solution won't work!! Since requirejs doesn't load the scripts sequentially, it is possible the plugin js file loads before jquery which will cause the execution to fail. Sorry for this.
If someone has another idea...

Resources