When I try to initialize an object declared/defined in a different file (but I believe it's been loaded via requireJS), it gives me ReferenceError: myTemplates is not defined. I have two files: main.js and templates.js.
In main.js (which is where I would like to load the object from templates.js and initialize it,
define(["jquery-ui", "templates"], function () {
var templates = new myTemplates(); // gives ReferenceError
alert( "Never reached this call" + $().jquery);
$(document).ready(function() {
alert( "Never reached this call " + $().jquery);
});
});
In templates.js, which just have an object named myTemplates with a function named test as follows
define(["jquery-ui"], function () {
alert( "This alert is raised, proving that jQuery/jQuery UI is loaded in templates.js " + $().jquery);
function myTemplates(){
this.test = function(){
alert('test');
return false;
};
};
});
For the config file for requireJS, named requireconfig.js, I have
requirejs.config({
"baseUrl": "scripts/lib",
"paths": {
"app": "../app",
"jquery" : [
"//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min",
"jquery-1.10.2.min"],
"jquery-ui" : [
"//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min",
"jquery-ui-1.10.3.min"],
"templates" : "../app/templates/templates"
},
shim: {
"jquery-ui": {
exports: "$",
deps: ["jquery"]},
}
});
requirejs(["app/main", "templates"]);
I'm pretty sure the jQuery and jQuery UIs are loaded properly in templates.js, but I can't understand why I'm getting ReferenceError for initializing myTemplates in main.js. Could anyone please take a look and help me out. Thank you.
p.s. The Github upload of the files/folders is here in case anyone wants to look at the folder/file hierarchy.
OK, two problems
in templates.js, once you defined a object, or function, you have to return it
function myTemplates(){ ... };
return myTemplates;
in main.js, you have to give a reference name for those defined objects, unless they are not AMD or defined in shim config.
define(["jquery-ui", "templates"], function ($ui, myTemplates)
give a try!
Related
I have two Javascript file loading from the same domain. Each JS performing different function and for that, I have used requirejs module loader.
My problem is, I have used require.config call under both js and baseUrl is different for both configuration.
JS1
require.config({
baseUrl : server + "js/", // server is 192.168.1.10:3000/
paths :
{
jquery : "jquery",
moment : "moment.min"
},
waitSeconds: 20
});
require(["jquery","moment"], function(jQuery,moment)
{
jQuery.noConflict();
window.moment = moment;
jQuery(function($)
{
window.$191 = $;
callback($191);
});
});
JS2
require.config({
baseUrl: "http://192.168.1.9:6060/App/resources",
paths:
{
moment: "js/moment.min",
ejs : "js/ejs"
}
});
require(["moment","ejs"],function()
{
callback("OK");
});
I am loading JS1 first followed by JS2, but when I am loading JS2 its baseUrl change by 1st one i.e. from JS1 (server+"js/") !! Which is totally wrong. Can some one point me out here, if something I have done wrong.
Nikos Paraskevopoulos has the right idea for one way (multiversion) to approach this, but I think there are two ways.
1. Using multiversion
Passing two configs to require.config() will return to you two unique require functions.
// It is important to give the config objects a "context" name.
// This is what keeps them unique.
var r1 = require.config({
context: "r1",
baseUrl: "//rawgithub.com/requirejs/text/2.0.10/"
});
var r2 = require.config({
context: "r2",
baseUrl: "//cdnjs.cloudflare.com/ajax/libs/require-text/2.0.10/"
});
In addition, even if you used the same baseUrl in each config in the sample above, each text module would be a unique instance because of the nature of multiversion support.
These can be used to load modules from different URLs. In the example below, text1 and text2 are different module instances, even though they are essentially the same file.
r1(["require", "text"], function(r, text1) {
// ...
});
r2(["require", "text"], function(r, text2) {
// ...
});
The "require" module is required as a dependency if you use the var myModule = require("..."); syntax within the module body.
If all your dependencies are declared in the dependency array then you do not need this.
(There is a simple example of this at this jsfiddle)
But back to your example, you can assign local require functions to each file, and load modules via that local require function.
JS1
(function () {
var r = require.config({
context: "JS1",
baseUrl: server + "js/", // server is 192.168.1.10:3000/
paths: {
jquery: "jquery",
moment: "moment.min"
},
waitSeconds: 20
});
r(["jquery", "moment"], function (jQuery, moment) {
jQuery.noConflict();
window.moment = moment;
jQuery(function ($) {
window.$191 = $;
callback($191);
});
});
}());
JS2
(function () {
var r = require.config({
context: "JS2",
baseUrl: "http://192.168.1.9:6060/App/resources/",
paths: {
moment: "js/moment.min",
ejs: "js/ejs"
}
});
r(["moment", "ejs"], function () {
callback("OK");
});
}());
Aside
It's unusual for modules to not start with a call to the define() function, however. Usually, config and the modules are in separate files. So you might have:
JS1-config.js and JS1.js
JS2-config.js and JS2.js
And JS1.js and JS2.js would be of the form:
define(["array", "of", "dependencies"], function(array_, of_, dependencies_) {
});
2. Using a consolidated require config
A cohesive application is probably better served with a single module loader configuration file. You have visibility on all the required modules, and it'll probably play better with the r.js optimiser, should you want to use that.
As such, I would recommend consolidating your configs into a single config for your application. This way you don't mix the module loader config with the code that actually uses the modules.
If you can't modify some of the code, then this could be tricky to do though.
E.g.:
var baseUrl1 = server + "js/";
var baseUrl2 = "http://192.168.1.9:6060/App/resources/";
require.config({
paths: {
jquery: baseUrl1 + "jquery",
moment: baseUrl1 + "moment.min",
//moment: baseUrl2 + "js/moment.min",
ejs: baseUrl2 + "js/ejs"
},
waitSeconds: 20
});
This assumes that both JS files can use the same "moment" module.
I'm having a bit of trouble with contexts in requireJS. What I'd like to is create a context, "mycontext", at the config stage (before I load any modules), and then have that context kept throughout. This is complicated because I am unfortunately required (<- ha!) to use the CommonJS syntax for my modules. So, if this is my base file looks like this:
base.js
contextReq = require.config({
context: 'mycontext',
baseUrl: 'http://www.example.com/src/',
paths:{
jquery: 'http://ajax.cdnjs.com/ajax/libs/jquery/2.0.3/jquery.min',
},
});
(function(){
contextReq(['require', 'topModule'], function(require, topModule){
topModule.initialize();
});
})();
Then, I load topModule:
http://www.example.com/src/topModule.js
define(['require', 'jquery', 'nestedModule'], function (require) {
var $ = require('jquery');
var other = require('nestedModule');
});
Will jQuery still be loaded only in mycontext? What if I go a level further:
http://www.example.com/src/nestedModule.js
define(function (require) {
var $ = require('jquery');
var oneMore = require('someOtherModule');
});
We already have access to jquery in this context, but will "someOtherModule" also be loaded in this context, or in the global "_" context? Is there any way to check if a module is already loaded before I make the require call?
Thanks!
Ok, so I figured this out myself. Require, locally or globally, has a very useful property called ".s" which lists, among other things, all of requires contexts. I ran "require.s.contexts" on to the console after my require has finished loading:
base.js
contextReq = require.config({
context: 'mycontext',
baseUrl: 'http://www.example.com/src/',
paths:{
jquery: 'http://ajax.cdnjs.com/ajax/libs/jquery/2.0.3/jquery.min',
},
});
(function(){
contextReq(['require', 'topModule'], function(require, topModule){
topModule.initialize();
});
})();
//Timeout, then see where we stand
setTimeout( function () {
console.log(require.s.contexts._);
console.log(require.s.contexts.mycontext);
}, 500);
The output was as follows:
//Console.log for context '_' (the default require context)
{
[...]
defined: [], //empty array, nothing has been loaded in the default context
[...]
}
//Console.log for context 'mycontext' (the default require context)
{
[...]
defined: [ //Filled out array; everything is loaded in context!
topModule: Object
nestedModule: Object
jquery: function (e,n){return new x.fn.init(e,n,t)} //jQuery function
],
[...]
}
So, in summary, my hunch was correct: when a top level requireJS module is loaded in a particular context, all modules loaded from within that top level module are loaded in context, even if the context is no longer specified.
I am trying to load KnockoutFire, a KnockoutJS plugin using RequireJS. It is only 1 file: https://github.com/hiroshi/knockoutFire/blob/master/knockoutFire.js
The plugin does two things:
Defines the global var "KnockoutFire"
Extends the core KnockoutJS ("ko") lib
So for this lib to load properly it needs to be able to access KnockoutJS through the global var "ko". Problem is I am loading KnockoutJS using proper AMD and there is no global "ko" available for KnockoutFire to reference. I have tried shimming both libs and various other tricks to get it to work, but I am stumped. Everything produces the error:
ReferenceError: ko is not defined
Here is what I am working with:
require.config({
enforceDefine: false,
baseUrl: 'assets/js/',
paths: {
'knockout': '//ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1'
},
shim: {
'knockout': { exports: 'ko' },
'knockoutfire': { exports: 'KnockoutFire', deps: ['knockout'] }
},
waitSeconds : 15
});
require(['knockoutfire'], function() {
log(KnockoutFire);
});
I've tried doing weird stuff too like:
require(['knockout'], function(ko) {
require(['knockoutfire'], function(kofire, ko) {
log(KnockoutFire);
});
});
Or:
define(['knockout'], function(ko) {
require(['knockoutfire'], function(ko) {
log(KnockoutFire);
});
});
If I download the third party lib and add this to it:
define(['knockout'], function(ko) {
<!--- third party lib --->
});
everything works fine.
Is there a way to achieve the same result without having to modify the third party lib?
When you need these scripts use order! plugin http://requirejs.org/docs/1.0/docs/api.html#order to ensure you load knockout before knockoutfire. i.e. in your file :
define('require','exports','order!knockout','order!knockoutfire',
function(req,exp,knockout,knockoutfire){
//trimmed
I think a closer look at http://knockoutjs.com/downloads/knockout-2.2.1.debug.js might reveal the answer. There is special AMD handling, and I'm not sure that's playing well with the things I've tried (using shim and exports).
This hack works though. We basically control the globals assignments with a bootstrap module.
require.config({
enforceDefine: false,
baseUrl: 'assets/js/',
paths: {
'jquery': 'http://code.jquery.com/jquery-1.9.1',
'knockout': 'http://knockoutjs.com/downloads/knockout-2.2.1.debug',
'knockoutfire': 'https://raw.github.com/hiroshi/knockoutFire/master/knockoutFire'
},
waitSeconds: 15
});
define("bootstrap", ['jquery', 'knockout'], function ($, ko) {
console.log("bootstrap", "jQuery " + $.fn.jquery, ko);
window.ko = ko;
var dfd = $.Deferred();
require(['knockoutfire'], function (kof) {
dfd.resolve(KnockoutFire);
});
return dfd.promise();
});
require(['bootstrap'], function (bootstrap) {
bootstrap.then(function () {
console.log("ko", ko, "KnockoutFire", KnockoutFire);
});
});
Outputs:
bootstrap jQuery 1.9.1 Object {exportSymbol: function, exportProperty: function, version: "2.2.1", utils: Object, cleanNode: function…}
ko Object {exportSymbol: function, exportProperty: function, version: "2.2.1", utils: Object, cleanNode: function…}
KnockoutFire Object {version: "0.0.3", utils: Object, observable: function, mapObservable: function}
Example here.
This answer was inspired by #Paul's answer:
define("globalko", ['knockout'], function (ko) {
window.ko = ko;
});
require(['knockoutfire', 'globalko'], function (kofire) {
console.log(kofire);
});
This loads both libs without error.
Anyone have any suggestions for KO or KOFire to make their libs easier to work with with AMD?
assuming you have something like following in knockoufire
define('require','exports','ko',function(req,exp,ko){
//trimmed
Try the following line on top of knockoutfire:
var ko = ko.ko
I'm trying to load jqplot as a requireJS module.
My main.js has a path and shim like this:
require.config({
, paths: {
plot: '../js/plugins/jqplot/jqplot.module'
}
, shim: {
'plot': { deps: ['jquery']}
}
});
Since this module is not needed on most pages, I'm waiting for the pageXYZ to be loaded and then inside a <script></script>, I'm calling:
require(['plot'],
function (plot) {
// do stuff
}
);
And my jqplot.module looks like this:
define(['../js/plugins/jqplot/jquery.jqplot'],
function () {
require([
'../js/plugins/jqplot/plugins/jqplot.barRenderer'
, '../js/plugins/jqplot/plugins/jqplot.logAxisRenderer'
, '../js/plugins/jqplot/plugins/jqplot.categoryAxisRenderer'
, '../js/plugins/jqplot/plugins/jqplot.canvasAxisTickRenderer'
, '../js/plugins/jqplot/plugins/jqplot.canvasTextRenderer'
, '../js/plugins/jqplot/plugins/jqplot.pointLabels'
, '../js/plugins/jqplot/plugins/jqplot.enhancedLegendRenderer'
],
function (){
return $.jqplot;
}
);
}
);
which returns the correct object with all sub-plugins defined and usable.
However, my Do stuff code runs BEFORE jqplot is assigned to $, so I'm still getting undefined errors when my code runs (I assume, because the files are all loaded, so requirejs starts running)
Question:
What can I do halt code execution until the jqplot has been assigned to $?
1) I think this line from your question:
define(['../js/plugins/jqplot/jquery.jqplot'],
should read:
define(['../js/plugins/jqplot/jquery.module'],
2) You do not need a shim, because you have a module definition that loads jqplot. So change your requirejs.config to
require.config({
, paths: {
plot: '../js/plugins/jqplot/jqplot.module'
}
});
3) your jqplot.module is not returning anything right now. Change it to:
define([
'../js/plugins/jqplot/jquery.jqplot'
],
function () {
var plot;
require([
'../js/plugins/jqplot/plugins/jqplot.barRenderer',
'../js/plugins/jqplot/plugins/jqplot.logAxisRenderer',
'../js/plugins/jqplot/plugins/jqplot.categoryAxisRenderer',
'../js/plugins/jqplot/plugins/jqplot.canvasAxisTickRenderer',
'../js/plugins/jqplot/plugins/jqplot.canvasTextRenderer',
'../js/plugins/jqplot/plugins/jqplot.pointLabels',
'../js/plugins/jqplot/plugins/jqplot.enhancedLegendRenderer'
],
function () {
plot = $.jqplot;
});
return plot;
});
This is all untested, but I think these should help
Answering this question and all the repeats, basic above answer is close but no cigar, as require is async, as such require could/will fire before define closure closes and returns, async safe solution below :
Nasty problem, as it's a chain of three dependencies
jquery is required for jqplot which is required for jqplot plugins, I have a simpler solution based on the same lines as the one above
first do your requirejs "main.js" config like so
requirejs.config({
paths: {
"jquery": "path/to/jquery-1.10.2.min",
// WORKAROUND : jQuery plugins + shims
"jqplot.core": "path/to/jquery-jqplot-1.0.8.min",
"jqplot": "jquery-jqplot-module-with-plugins-1.0.8"
},
shim: {
"jqplot.core": {deps: ["jquery"]},
"jqplot": {deps: ["jqplot.core"]}
}
});
create a wrapper file module file called "jquery-jqplot-module-with-plugins-1.0.8.js", containing :
// wraps jquery jqplot plugin in define statement
define([
"jquery",
"path/to/jqplot.highlighter.min",
"path/to/jqplot.cursor.min",
"path/to/jqplot.dateAxisRenderer.min",
"path/to/jqplot.canvasTextRenderer.min",
"path/to/jqplot.canvasAxisLabelRenderer.min",
"path/to/jqplot.enhancedLegendRenderer.min",
"path/to/jqplot.pieRenderer.min",
"path/to/jqplot.donutRenderer.min",
], function($) {
var jqplot;
jqplot = $.jqplot;
return jqplot;
});
Then when ever you need jqplot with those plugins, simply call for "jqplot" which will load "jquery" then "jqplot.core" then all the jqplot modules, then finally return the jqplot object :)
require(["jquery", "jqplot"], function ($, $jqplot) {
console.log("Success..Inside Require JS");
console.log("Plot...", $.jqplot, $jqplot);
});
or
define(["jquery", "jqplot"], function ($, $jqplot) {
console.log("Success..Inside Define JS");
console.log("Plot...", $.jqplot, $jqplot);
});
tada! :)
ps jquery plugins are evil, no suggestion how to fix that situation, just a statement of fact
cheers
Ant
I'm fairly new to RequireJS and I've run into a bit of a problem. I've written a little framework built on Backbone using RequireJS and I want it to be re-usable in different projects. So, with some searching I learned that require allows packages. This seemed like what I was looking for. I have a main.js file to launch my app that essentially looks like this:
require.config({
packages: ['framework']
});
require(['framework'], function(framework) {
framework.createDash();
});
Then in the same directory as my main.js I have another directory called "framework" which contains another main.js which looks like this:
define(function(require, exports, module) {
exports.createDash = function(dash, element) {
require(['dash/dash.model', 'dash/dash.view'], function(DashModel, DashView) {
return new DashView({
model: new DashModel(dash),
el: element ? element : window
});
});
};
});
In searching I found this page which indicates that the 'require' argument should be scoped to the submodule. However, when I try to require things they are still relative to my original main.js. I've tried a number of things and searched for hours to no avail. Is there any way I can have my require/define calls within my package included relative to the main.js in it's root?
You need to define your submodule as package in the require configuration:
require.config({
packages: [
{ name: 'packagename',
location: 'path/to/your/package/root', // default 'packagename'
main: 'scriptfileToLoad' // default 'main'
}]
... some other stuff ...
});
To load your module you just need to use your 'packagename' at the requirements:
define(['jquery', 'packagename'], function($, MyPackage) {
MyPackage.useIt()
});
In your package you must use the ./ prefix to load your files relative to your submodule:
define(['globalDependency', './myLocalFile'], function(Asdf, LocalFile) {
LocalFile.finallyLoaded();
});
There is a useful shortcut: If your package name equals to your location and your main file is called 'main.js', then you can replace this
packages: [
{ name: 'packagename',
location: 'packagename',
main: 'main'
}]
to this:
packages: ['packagename']
As far as I can see, you already tried to define a package but did you also use the ./ prefix? Without this prefix require will try to find the files in it's global root-path. And without a package, ./ will be useless because the relative path is the same as the global root-path.
Cheers
I figured out the answer to my question, and the solution (they were not the same apparently). I guess I'll post it here in case it can help someone else in the future.
Essentially what I was wanting was to load my framework within its own context. I found the context option under the configuration section on require's website and an example of how to use it. Originally I tried this by doing something like:
var req = require.config({
baseUrl: 'framework',
context: 'framework',
paths: {
jQuery: 'lib/jquery/jquery-1.7.min.js',
Underscore: 'lib/underscore/underscore.min.js',
Backbone: 'lib/backbone/backbone.min.js',
etc...
}
});
req(['main'], function() {});
There were two problems with this. First, my 'req' variable was being defined outside of the framework, but I wanted the framework to define it's own paths. And second, whenever a file outside of the framework would require a file within the framework, which would in turn require 'jQuery', for example, then jQuery (or whatever else) wouldn't be required from within the context of the framework instance of require and so it couldn't find the file.
What I ended up doing was defining my framework's main.js to look something like this:
var paths = {
jQuery: 'lib/jquery/jquery-1.7.min.js',
Underscore: 'lib/underscore/underscore.min.js',
Backbone: 'lib/backbone/backbone.min.js',
etc...
};
define(function() {
var exports = {};
exports.initialize = function(baseUrl, overridePaths, callback) {
if(!overridePaths) {
overridePaths = {};
}
if(baseUrl && baseUrl[baseUrl.length - 1] != '/') {
baseUrl = baseUrl + '/';
}
var fullpaths = {};
for(var path in paths) {
// Don't add baseUrl to anything that looks like a full URL like 'http://...' or anything that begins with a forward slash
if(paths[path].match(/^(?:.*:\/\/|\/)/)) {
fullpaths[path] = paths[path];
}
else {
fullpaths[path] = baseUrl + paths[path];
}
}
var config = {paths: fullpaths};
for(var pathName in overridePaths) {
config.paths[pathName] = overridePaths[pathName];
}
require.config(config);
// Do anything else you need to do such as defining more functions for exports
if(callback) {
callback();
}
}
return exports;
});
And then in my project's main.js file I just do this:
require(['framework/main'], function(framework) {
// NOTE: This setTimeout() call is used because, for whatever reason, if you make
// a 'require' call in here or in the framework without it, it will just hang
// and never actually go fetch the files in the browser. There's probably a
// better way to handle this, but I don't know what it is.
setTimeout(function() {
framework.initialize('framework', null, function() {
// Do stuff here
}
}, 0);
});
This takes whatever is passed in to the framework's initialize() method for 'baseURL' and prepends that to any paths that the framework defines that do not start with a forward slash or 'anything://', unless they are override paths. This allows the package using the framework to override things like 'jQuery'.
This worked for me, adding a "./" prefix to the module names:
define(function (require, exports, module) {
exports.createDash = function (dash, element) {
require([ './dash/dash.model', './dash/dash.view' ], function (DashModel, DashView) {
return new DashView({
model : new DashModel(dash),
el : element ? element : window
});
});
};
});
A process that worked well for me for allowing a package with submodules to be used directly from data-main or from an outside framework, assuming that a main.js (or other package main) is called by a particular name, was to use var baseUrl = require.toUrl('packageName') + '/../' as a prefix to a require.config({ paths: { ... } }) configuration file. For instance:
var music21Base = require.toUrl('music21') + '/../';
require.config({ paths: {
'jquery': music21Base + 'ext/jquery/jquery.2.1.10.min';
'subModuleLoader': music21Base + 'src/subModuleLoader';
} });
The setting of context: "xxx" worked fine for calling normal modules with ./modName but did not work for the paths argument for me.