My library use kriskowal/Q promises library and now I'm trying to load (with requirejs) application that use my library so I put all paths and shims and my requirejs.config section looks like this:
requirejs.config({
baseUrl: './',
catchError: false,
paths: {
beril: '../engine/build/src/bundle',
lodash: 'bower_components/lodash/lodash',
three: 'bower_components/three.js/build/three',
q: 'bower_components/q/q',
},
shim: {
lodash: {
exports: '_'
},
three: {
exports: 'THREE'
},
q: {
exports: 'Q'
},
beril: {
deps: ['lodash', 'three', 'q'],
exports: 'beril'
},
}
});
After this I suppose variables THREE, _ and Q to be defined in global space.
Now I'm loading and runinng application with this simple line:
require(['beril', 'js/stepbystep/' + $stateParams.page + '/app'], (beril, app) => app());
but then I'm getting error: ReferenceError: Q is not defined even though I can see in Chrome's network inspector that Q library have been loaded.
Also all the rest dependencies (THREE and _) are defined. Seems like requirejs`s shim does not work for this library. Can it be or am I missing something?
So what am I'm doing wrong and how should I deal with this situation?
I found solution and it was to add init function to my library's shim and then add Q as global object manually so my shim section now looks like this:
shim: {
lodash: {
exports: '_'
},
three: {
exports: 'THREE'
},
q: {
exports: 'Q'
},
beril: {
deps: ['lodash', 'three', 'q'],
exports: 'beril',
init: function(lodash, three, q){
window.Q = q;
}
},
}
however I don't clearly understand why it does not work without this and are there better ways to deal with this situation.
There are a few problems with your configuration. For one thing, you have unnecessary shim configurations. I installed lodash just now (with bower install lodash) and searched its code. It calls define. So you must not set a shim for it. RequireJS won't give you an error but you will get undefined behavior. The same is true of Q: it calls define so, no shim for it. Last I checked, THREE needs a shim.
The fact that Q calls define is also why it does not leak the symbol Q into the global space. It acts like a well-behaved AMD-module.
Ok, so how can we get Beril to find Q? Your solution works but I find it slightly iffy. The problem is that init is executed after the shimmed module is loaded. As long as Beril refers to Q only in the body of functions to be executed later, it will work. And I guess this is how Beril works now. However, if a new version of Beril needs to refer to Q when the file that contains Beril is first executed, it will fail because Q does not exist yet.
One way to work around the problem that is future-proof is to use map and some glue. Keep your shim for beril but remove the init. Define a module named q-glue:
define(['q'], function (Q) {
window.Q = Q;
return Q;
});
And declare this map in your configuration:
map: {
beril: {
q: "q-glue"
}
}
This says "when q is requested from beril load q-glue instead." By doing this, window.Q will be defined before Beril is loaded.
I take it you are the author of Beril. I urge you to make your library AMD-compatible so as to spare users of your library having to go through configuration pains to get it working with AMD-loaders (like RequireJS).
It worked for me after I downgraded to version 0.9 up until 1.0.1 as mentioned in the readme. The current version 2.0.2 has significant braking changes as mentioned by Kris Kowal here.
I didn't have the need to set the global variable as the older version checks the environment and does so if loaded before require.
You need to add q to require()...
require(['beril', 'q', 'js/stepbystep/' + $stateParams.page + '/app'], (app, beril, q) => app());
Related
JustGage uses Raphael, which as is well-discussed here, is not AMD compliant (and so doesn't work with Require.js).
I have not used Require.js before, nor done a lot of JS, so I am battling to get my head around this. There has been a lot of trial and error ;)
Using the approach suggested here, I have split the Raphael modules out into separate files and included them separately, as well as making a guess as to what to do for JustGage.
require.config({
paths: {
//other links removed
'eve': 'vendor/eve/eve',
'raphael-core': 'vendor/raphael/raphael.core',
'raphael-svg': 'vendor/raphael/raphael.svg',
'raphael-vml': 'vendor/raphael/raphael.vml',
'raphael': 'vendor/raphael/raphael.amd',
'justgage': 'vendor/justgage/justgage.1.0.1.min'
},
shim: {
'eve': {
exports: "eve"
},
'raphael': {
deps: ['eve'],
exports: "Raphael"
},
'justgage': {
deps: ['raphael'],
exports: "JustGage"
}
}
});
But the instructions then say "After the above configuration, you can start using Raphael like other require-js modules" which is not so helpful ;)
I think I need to do something in main.js?
In my cshtml page I have
require(["raphael", "justgage"], function(JustGage) {
$(function() {
var a = new JustGage({
id: "pvgauge",
value: #Model.GaugeValues.PV,
min: #Model.PVGauge.MinValue,
max: #Model.PVGauge.MaxValue,
title: "Personal Volume",
label: "PV",
levelColors: gaugeSettings.levelColors,
levelColorsGradient: gaugeSettings.levelColorsGradient,
showInnerShadow: gaugeSettings.showInnerShadow,
shadowSize: gaugeSettings.shadowSize,
labelFontColor: '#7ACE30',
titleFontColor: gaugeSettings.titleFontColor,
valueFontColor: gaugeSettings.valueFontColor
});
});
});
Now this at least finds JustGage, but now gives the error 'Raphael' is undefined.
(I have also tried just doing a script include directly in the cshtml file but get the error 'Mismatched anonymous define() module: function (eve) {')
Is my understanding correct that Require.js means things are not in global scope? And JustGage is expecting Raphael to be in global scope?
Any help on getting JustGage working? Or recommendations for an equivalent library for "speedo"-type gauges that will work with Require.js?
almost there, you need add it to the function as well, so it's available to JustGage.
require(["raphael", "justgage"], function(raphael,JustGage) {
If justgauge is a module then you should load the dependency in the module, as it will be looking in that module for raphael, however as you've already loaded it, it should work,
it's easier to keep track of your dependencies and load them where needed,
define(['module' , "pathto/raphael"], function (module, raphael) {
This worked for me:
require('eve');
window.Raphael = require('raphael');
require('justgage');
I'm working on a JavaScript module that uses jQuery, some functions of jQuery UI (draggable) and jPlayer. Recently I made myself familiar with requireJS to manage the dependencies properly.
I don't want to produce conflicts with a possibly already existing jQuery version that the site that includes my script uses. For this reason I am mapping the jQuery dependencies to a module "jquery-private" with a call of noConflict(), as is described in the requireJS guide.
As jQuery UI takes up a lot of space, I would also like to just include the modules that I am actually using. ui.draggable has the dependencies ui.core, ui.mouse and ui.widget, so I should have to include these 4 modules.
My problem is that I would like the jQuery UI modules and the jPlayer module to use my own version of jQuery, but obviously it isn't accessible by the global $ variable after I called the noConflict() method. Unfortunately neither jQuery UI nor jPlayer are AMD modules, so I needed to make shim configurations for them.
Here is my definition of the dependencies:
require.config({
baseUrl: 'javascript/modules',
paths: {
jquery: 'jquery-2.1.3',
jPlayer: 'jquery.jplayer',
uiCore: 'jquery.ui.core',
uiMouse: 'jquery.ui.mouse',
uiWidget: 'jquery.ui.widget',
uiDraggable: 'jquery.ui.draggable'
},
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: {
jPlayer: {
deps: ['jquery']
},
uiCore: {
deps: ['jquery']
},
uiMouse: {
deps: ['jquery','uiCore']
},
uiWidget: {
deps: ['jquery','uiCore']
},
uiDraggable: {
deps: ['jquery','uiCore','uiMouse','uiWidget']
}
}
});
require(["json","jquery","jPlayer","uiDraggable"], function(json,___jQuery,jplayer,uiDraggable) {
(...)
}
Obviously this code produces errors as the $ variable in the jQuery UI modules is not defined.
Is there any way to pass my own jQuery object to modules? The top answer in another thread (How use require.js to load jQuery with noConflict) suggests that what I am trying to do is not possible, but maybe there is some other way to do it?
If there is none, I probably have to use global variables and heavily edit the included modules, which kind of makes it questionnable why to use a dependency management library like requireJS in the first place...
I found the following code on top of each module in jquery.ui:
(function( factory ) {
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
define([ "jquery" ], factory );
} else {
// Browser globals
factory( jQuery );
}
}(function( $ ) {...});
And it means jquery.ui checks when global AMD "define" function is defined and uses 'jquery' as AMD reference for module.
It will use no conflict of jquery based on requirejs recommendation in this and this.
And about how to use jQuery with AMD.
I'm upgrading from jQuery 1.8 to 1.9 and since jQuery.browser() is removed, I will use jQuery Browser Plugin.
My requirejs config file (loaded using data-main="") looks somewhat like this:
(EDITED - added more code snippets)
main-comp.js
require.config({
paths: {
jquery: 'libs/jquery/jquery1.9.1.min',
utils: 'modules/utils',
myController: "controllers/myController",
browserPlugin: 'libs/jquery/jquery.browser.min'
},
shim: {
browserPlugin: {
deps: ['jquery']
}
}
});
require(['myController', 'jquery'], function (controller, $) {
$(controller.start);
}
);
moduls/utils.js
define(['browserPlugin'], function () {
return {
browser: $.browser
};
});
myController.js
define(['utils'], function (utils) {
function start() {
console.log(utils.browser.msie)
}
return {
start: start
};
});
Everything seemed to work properly, but then I saw that sometimes in IE only I get a 'jQuery' is undefined (it's a capital Q there) or '$' is undefined errors from the jquery.browser.min.js file.
I thought the deps means that jquery will load before the jquery.browser file but apparently this isn't always the case. I tried following this answer and add exports: "$.fn.browser" but with no success.
When running an optimized version (minify+uglify using r.js) I haven't encountered it.
What am I doing wrong?
You need to ensure you reference $ as a parameter in the require callback. Like so:
require(['myController', 'jquery'], function (controller, $) {
$(controller.start);
}
);
This ensures that jQuery is available to use. It is a bit of an odd one as it will expose itself globally anyway so it will sometimes work regardless, but the correct way is to explicitly require it and use it inside the callback as a parameter.
It looks like you are missing jquery dependency in moduls/utils.js, please try:
define(['jquery', 'browserPlugin'], function ($) {
return {
browser: $.browser
};
});
and also, just to be on the safe side, add jquery to your shim :
jquery: {
exports: "$"
},
By the way, why don't you use $.browser in your code and just load the jquery plugin using the shim configuration?
I had the same problem, the script in data-main is loading asynchronously, that means that it may load after the scripts it defines.
The solution is to load another script with the require.config right after the require.js script.
data-main Entry Point Documentation.
I'm having issues trying to load ckeditor via requirejs (I've tried converting the main ckeditor js file into individual modules but that has just caused all hell to break loose) and so I'm now checking to see if there is a very simple way to do this that I've missed.
I know requirejs allows you to load normal js scripts so maybe just loading the ckeditor.js file (un-edited, so it's still an IIFE/self-executing function) - would that work with requirejs or if you're using requirejs for loading modules, does the entire project then need to be module based?
Any help appreciated.
Kind regards,
Mark
Alternatively, you can create a RequireJS shim to load things in the correct order, and alias proper RequireJS module names to the CKEditor distribution files.
This means your module still declares it is dependant on CKEditor, which is a lot nicer than having it just show up by magic.
require.config({
shim: {
'ckeditor-jquery':{
deps:['jquery','ckeditor-core']
}
},
paths: {
"jquery": '/javascript/jquery-1.7.1/jquery.min',
'ckeditor-core':'/javascript/ckeditor-3.6.4/ckeditor',
'ckeditor-jquery':'/javascript/ckeditor-3.6.4/adapters/jquery'
}
});
then in a module you can depend on ckeditor-jquery (or ckeditor-core for that matter, if you don't need the jQuery integration) and know it'll be available:
require(
[
"jquery",
"ckeditor-jquery"
],
function( _jquery_ ) {
$('#editorContent2').ckeditor({
customConfig : '',
skin:'office2003'
});
}
}
Another way to do that:
var require = {
"shim": {
"path/foo/ckeditor/ckeditor": { "exports": "CKEDITOR" }
}
};
define(['moduleX', 'path/foo/ckeditor/ckeditor'], function (x, ckeditor) {
ckeditor.editor.prototype.fooFunc = function() {
};
});
OK, it seems I answered my own question here.
Instead of trying to break ckeditor down into modules I just used RequireJs to load the script in it's entirety.
require(['require', 'dependancy-A', 'dependancy-B', 'dependancy-C'], function(require, A, B, C){
// this = [object DOMWindow]
// CKEDITOR_BASEPATH is a global variable
this.CKEDITOR_BASEPATH = '/ckeditor/';
require(['/ckeditor/ckeditor'], function(){
// Code to create a new editor instance
});
});
```
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;
});