requirejs config gives ReferenceError: can't find variable $ - javascript

Maybe I have fundamentally misunderstood how requirejs config works but I thought my configuration below made some libraries global so I could just use them in other files while only having to require and define files that I needed to use within the individual script. However I cannot reference $ (jQuery) in my application code without getting a reference error indicating it is not globally accessible. I've isolated the problem to the simple example below.
My file set up is as follows:
test
|
|-index.html
|-TestApp.js
|-MainApp.js
|-lib
| |-require.js
| |-jquery.js
| |-loadash.js
| |-backbone.js
|-css
|-test.css
The library file versions are RequireJS 2.1.22, jQuery 2.0.3, Loadash 3.10.1 and Backbone 1.2.1. I'm just trying to set up my environment and the approach I am taking is to pass my TestApp.js file to require.js to load the required files and bootstrap the application code in MainApp.js. The script in index.html is as follows:
<!DOCTYPE html>
<html>
<head>
<link rel='stylesheet' type='text/css' href='css/test.css'/>
</head>
<body>
<div></div>
<script src="./lib/require.js" type="text/javascript" data-main="./TestApp.js"></script>
</body>
</html>
The referenced css script file simply ensured the div is visible as an orange square. See below:
div {
height: 100px;
width: 100px;
background-color: #FA6900;
border-radius: 5px;
}
It's the script line in index.html that then kicks off the application code by passing my configuration file to requirejs. This is the TestApp.js passed across as data-main. The TestApp.js is here:
require.config({
paths: {
'jquery': 'lib/jquery',
'lodash': 'lib/lodash',
'backbone': 'lib/backbone'
},
map: {
'*': {
// Backbone requires underscore. This forces requireJS to load lodash instead:
'underscore': 'lodash'
}
},
shim: {
jquery: {exports: '$'},
underscore: {
deps: ['jquery'],
exports: '_'
},
backbone: {
deps: ['underscore'],
exports: 'Backbone'
},
TestApp: {
deps: ['backbone'],
exports: 'TestApp'
}
}
});
require(['MainApp'], function(MainApp) {
MainApp.run();
});
The file above references the paths to the library files I want to use, I then remap loadash to be loaded when underscore is required (I need some of the extra loadash capability), I then use the shim to ensure the dependancies are correct as the files are loaded. Passing this config file to require.js in the index.html seems to be working as all of the files are showing as loaded in my browser. However the problem seems to be they do not appear to be globally accessible as I thought they would be.
Following the config section the last require call loads the MainApp.js file and calls the exposed run function. The MainApp.js looks like this:
define(function(require) {
var run = function() {
$(document).ready(function() {
$('div').click(function() {
$('div').fadeOut('slow');
});
});
};
return {
run: run
};
});
As far as I understood I should not need to require the files I already mentioned in the require config, I thought they should be loaded and available to this code. This is where I have misunderstood what is going on or have missed a step out. The exposed run function is being called but the first line that calls $ throws the error:
ReferenceError: Can't find variable: $
So my questions are:
What have I got wrong in my thinking?
(or) What am I doing incorrectly?
What should I be doing in order to preload and make available
frequently referenced libraries so that I do not need to require and
define them in every file I have?

As far as I understood I should not need to require the files I already mentioned in the require config, I thought they should be loaded and available to this code.
You misunderstood how RequireJS works. You should read the documentation from start to finish. For now, here are things you should change.
You should require jquery in your MainApp module:
define(function(require) {
var $ = require("jquery");
You should remove your shims that you have for jquery, underscore and backbone as they all call define and shim is only for code that does not call define. I don't know what TestApp is but if it is your own code, you really should make it into a proper AMD module and remove the shim.

#Louis has made me realise the error in what I was doing above. Changing the shim in TestApp.js so that is reads:
MainApp: {
deps: ['backbone'],
exports: 'MainApp'
}
Corrected the problem, now Backbone, $ and _ are all available to the rest of my application code without cluttering up each files require. i.e. I do not need to begin every file with:
define (['lib/jquery', 'lib/loadash', 'lib/backbone'], function($, _ , Backbone) {
Given in my actual app the list of common deps is quite large this means I only need to define locally used resources and can control the paths from a single location.

Related

require is not loading modules properly

fter including require tag the application is behaving abnormal way .is there any way i can bootstrap my application apart from below code .
main.js
require(['/module.js'], function() {
angular.element(document).ready(function () {
angular.bootstrap(document, ['myApp']);
});
});
When I written as single file js file the code is working properly.
module.js
var name = 'myApp';
angular.module(name, [])
.controller('Controller', require(['controller.js']))
.factory('Service', require(['service.js']))
.filter('Number', require(['filter.js']));
I have included my main.js in index.html . index html has 3 views i am displaying them based on ng-show from index.html.
The problem is module.js loading properly and js files too. Script is not executing properly so that my entire index.html page including 3 views displayed automatically with error messages.
Control is not going to controller.js/service.js
Error :
Error: Unknown provider: depsProvider <- deps .
Did i miss any define code? Thanks in advance
Angular does not support AMD by default, You need to config angular to export angular object. Please check out the this post for more details.
require.config({
paths: {
'angular': '../lib/angular/angular'
},
shim: {
'angular': {
exports: 'angular'
}
}
});
Your module.js should be defined with define method of requirejs and it should return module.
You can omit file extesion (.js) while using requireJs

Backbone.js + require.js : Wait until file is loaded

I'm using backbone.js and require.js. I have a script with files dependencies but the problem is that a file is not loaded before executing my script. So, a function is not defined. Here is the code exemple :
define([
'jquery',
'jqueryUi',
'holder',
'knob',
'jquery.ui.widget',
'iframeTransport',
'fileupload',
'knobScript',
], function($, ui, Holder) {
$(document).ready(function() {
$('#upload').fileupload({...}); // This one is unedefined because the script from the file fileupload is not completely loaded
});
});
Is someone has a solution to be sure that the script fileuplaod called in define is fully loaded before executing the script with the function (functionFromFileupload) ?
Thank for your help
To complement Evgeniy's comment: The problem is not that fileupload is loaded after your function. It will be loaded before running your function, that is the contract of Require. (If you can confirm it doesn't, then it would probably be a misconfiguration or less probably a bug of Require.)
Most probably the problem is that, sometimes, fileupload may be loaded before jQuery. Thus, it does not find the jQuery object to plug to and $(...).fileupload(...) fails. Use shim in the Require configuration, e.g. as:
require.config({
...
shim: {
fileupload: {
deps: ["jquery"]
}
...
}
...
});
You will probably have to shim other things too, e.g. jQueryUI.

How to properly define shim config with requirejs

I have jQuery and a jQuery plugin loaded via RequireJS.
This is how my requirejs.config looks like:
requirejs.config({
baseUrl: "http://mysite.example.com",
"paths": {
// libraries
"jquery": "Static/js/library/jquery/jquery-1.10.2",
"jquery_sortable" : "Static/js/library/jquery-sortable/jquery-sortable",
shim: {
'jquery_sortable': ['jquery']
}
}
});
When I refresh the page two times or more very quickly, sometimes I get an exception in the plugin code that:
Uncaught ReferenceError: jQuery is not defined.
Basically, my plugin does not use the shim I have set for it.
What is the most reliable way to specify my shim config ??
Could be because you were not constructing as expected. As you notice you were putting shim inside paths. May be.
"paths": {
// libraries
"jquery": "Static/js/library/jquery/jquery-1.10.2",
"jquery_sortable" : "Static/js/library/jquery-sortable/jquery-sortable",
shim: {
'jquery_sortable': ['jquery']
}
}
-------EDIT AFTER COMMENT------
Maybe trying to define the dep as declared in the manual?
'foo': {
deps: ['bar'],
...
source: http://requirejs.org/docs/api.html#config-shim
It's weird because all the examples I have seen online put the shim config at the last bit of the requirejs.config but putting it at the top seemed to solve MY problem.
requirejs.config({
baseUrl: "http://mysite.example.com",
shim: {
'jquery_sortable': ['jquery']
},
"paths": {
// libraries
"jquery": "Static/js/library/jquery/jquery-1.10.2",
"jquery_sortable" : "Static/js/library/jquery-sortable/jquery-sortable"
}
});
I feel that this occurs because RequireJS is loading scripts asynchronously. This happens for performance reasons, i.e. scripts will be loaded in parallel. This is OK for normal AMD modules; RequireJS will keep the dependency tree from the define(["deps"], function(){...}) calls but will defer the execution of function() until its dependencies are resolved.
However with non-AMD, shimmed modules (like jQuery-UI), the entire script will be executed on load. This means that, if by any chance the "sortable" is loaded before "jquery", it will not find its dependency and fail as you write.
I believe the only robust workaround is to include jQuery as a plain old <script> tag, right after require.js. This way you cannot use the data-main attribute to load your entry point, you will have to require it separately:
<script src="scripts/lib/requirejs/require.js"></script>
<script src="scripts/lib/jquery/jquery.js"></script>
<script>
require(["app/bootstrap"]);
</script>

Loading Angular from CDN via RequireJS is not injected

In my project I want to use RequireJS and bootstrap my app as follows:
requirejs.config({
baseUrl: 'scripts/vendor',
paths: {
jquery: [
'https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min',
'jquery'
],
angular: [
'http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min',
'angular'
],
app: '../app'
}
});
require(['require', 'jquery', 'angular', 'app'], function(require, $, angular, app) {
console.log(require);
console.log($);
console.log(angular);
console.log(app);
});
On my index.html only RequireJS is loaded via script tag, where the RequireJS loads the above code.
What works:
- in my Network monitor I can see that RequireJS, jQuery, Angular and app are loaded
- The console.log messages print correct for require, jQuery and app
The angular object is somehow undefined. But if I don't load it from CDN and use my local load, it works! The local file is a RequireJS wrapper that looks like this:
define(['/components/angular/angular.min.js'], function () {
return angular;
});
How do I get this work with Angular'S CDN? Or does this depend on support from Angular?
First, you are confusing "paths" with "shim"
Path is good, don't go for "shim" behavior. But, you need to make your "paths" proper:
paths: {
jquery: 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min',
// NOTE: angular is "plain JS" file
angular: 'http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min',
app: '../app'
}
Then, you need to let go of the need to have something returned to you... Just "use the force, Luke" :) and expect the right globals to be there when you need them:
require(['jquery', 'app', 'angular'], function($, app, thisValueDoesNotMatter) {
// you don't need to wrap "require" Just use global
console.log(require);
console.log($);
console.log(app);
// note, angular is loaded as "plain JavaScript" - not an AMD module.
// it's ok. It returns "undefined" but we just don't care about its return value
// just use global version of angular, which will be loaded by this time.
// because you mentioned it in your dependencies list.
console.log(window.angular);
});

How to load Underscore library with RequireJS?

require(['underscore'], function ($, _) {
...
});
Doesnt work! (_ is not a function)
How to manage it?
Note that underscore.js doesn't register itself as an AMD module (though it did for a brief time in earlier versions), thus it can't be used in a require() call without some configuration using "shim:" like so:
require.config({
paths: {
jquery: 'lib/jquery.min',
underscore: 'lib/underscore-min'
}
shim: {
"underscore": {
exports: "_"
}
}
});
See the docs at: http://requirejs.org/docs/api.html#config-shim
Before shim: was added to require.js, you could do something similar with the plugin use.js (in case you need to use an older version of require.js).
As of this writing, the current version of require.js is 2.1.8.
Alternatively, you can use lodash.js as a drop-in replacement for underscore.js - it does register itself as an AMD module, so you can use it with no extra config: http://lodash.com/
I think the problem is the order of args passed in to your callback.
Should be:
require(['underscore'], function (_, $) {
...
});
Also you need to be using underscore version 1.2.1 which added this functionality.
require(["underscore"], function() {
console.log(_ === window._);
});
it all depends where the script is based.
since i don't see you specified a baseUrl, the baseUrl will be the default,
that means, either 2 things:
your script is directly inside a html file, and in your case it
will thus look for underscore.js in the same directory of the html
file
your script is in a javascript file referenced by your html
file, it will now search for underscore.js in the directory of your
custom javascript file.
check if the underscore.js is actually there.
Here are the checkpoints for you to make sure what you need works
Get require-jquery.js and put it to your /js-root dir
Add to your HTML, right before the closing </body> tag: <script data-main="/js-root/main-js-file-name" src="/js-root/require-jquery.js"></script>
Get underscore adapted for AMD, and put it to /js-root dir as well
In main-js-file-name.js
write:
require(["jquery", "underscore"], function ($, _) {
...
});
Similarly, in your non-main AMD JS files, when defining a module, to use _, write:
define(["jquery", "underscore"], function ($, _) {
...
return theModuleObjectOrFunction;
});

Categories