I'm just getting started with require.js. I have successfully wrapped jquery, some plugins, and a couple of my own modules. I'm trying to interact with my modules (or jquery) from Firebug (or Google Chrome's JS console), and I'm not having much luck.
What is the correct way to access these modules from the console?
Say we have module /app/scripts/methodsModule.js that returns a few methods:
define({
someMethod: function() {
// do stuff
},
anotherMethod: function() {
// do some more stuff
}
});
In our data-main file /app/scripts/main.js we have:
require(['methodsModule'], function(methods) {
methods.someMethod() // call someMethod
methods.anotherMethod() // call anotherMethod
})
Once requireJS loads up our data-main, we can access any modules that have already been loaded by requireJS from the javascript console command line like so:
>> methods = require('methodsModule'); // requireJS has module methodsModule stored
>> methods.someMethod() // call someMethod
>> methods.anotherMethod() // call anotherMethod
If a module hasn't been loaded by a call to require() or define(), we have to pass our own callback for the require function to call after the module has been loaded:
>> myCB = function(methods) { methods.someMethod() }
>> require(['methodsModule'], myCB)
Otherwise, requireJS throws an error saying that the module has not yet been loaded..
There is a way without using callbacks.
If you module was not required in console or you application before, you can just require it first:
require(['methodsModule']);
after that you can use "dynamic" require to access it:
require('methodsModule').someMethod();
Related
I'm writing tests for a JS application using Jasmine and testdouble.js as a mocking library. I am using AMD format to organize code in modules, and RequreJS as a module loader. I was wondering how to use testdouble.js to replace dependency for the module being tested that is in AMD format and it is loading via RequireJS. The documentation is unclear about this or I am missing something, so if someone could point me in the right direction.
I'll post the example bellow that illustrates my setup and the problem that I am facing.
car.js
define("car", ["engine"], function(engine) {
function drive = {
engine.run();
}
return {
drive: drive
}
});
engine.js
define("engine", function() {
function run() {
console.log("Engine running!");
}
return {
run: run
}
});
car.spec.js
define(["car"], function(car) {
describe("Car", function() {
it("should run the motor when driving", function() {
// I am not sure how to mock the engine's object run method
// and where to place that logic, in beforeEach or...
td.replace(engine, "run");
car.drive();
// How to verify that when car.run() has executed, it calls this mocked method
td.verify(engine.run());
});
});
});
testdouble.js does not have any explicit support for AMD modules. The only module-related tricks it offers are Node.js specific and built on top of Node's CJS module loader.
What you would need to do in this case is require from the test a reference to engine and replace the run property, which it seems like you've done (your example is incomplete).
If you do this, don't forget to run td.reset() in an afterEach to restore the original properties to anything you replace!
While working on a Web app using Webpack to manage JavaScript dependencies, I stumbled upon the problem i'm going to describe.
Loading dependencies passing strings to require() works beautifully:
// main.js
var jQuery = require('jquery');
Here, jquery is installed with Bower, and Webpack is correctly configured to automatically resolve Bower modules.
Now, I'm working on the problem of conditionally loading modules, with particular regard to the situation where modules have to be downloaded from a CDN, or from the local server if the CDN fails. I use scriptjs to asynchronously load from the CDN, by the way. The code I'm writing is something like this:
var jQuery = undefined;
try {
jQuery = require('jquery-cdn');
} catch (e) {
console.log('Unable to load jQuery from CDN. Loading local version...');
require('script!jquery');
jQuery = window.jQuery;
}
// jQuery available here
and this code works beautifully as well.
Now, since I obviously have a lot of dependencies (Handlebars, Ember, etc.) that I want to try to load from a CDN first, this code starts to get a little redundant, so the most logical thing I try to do is to refactor it out into a function:
function loadModule(module, object) {
var lib = undefined;
try {
lib = require(module + '-cdn');
} catch (e) {
console.log('Cannot load ' + object + ' from CDN. Loading local version...');
require('script!' + module);
lib = window[object];
}
return lib;
}
var jQuery = loadModule('jquery', 'jQuery');
var Handlebars = loadModule('handlebars', 'Handlebars');
// etc...
The problem is that Webpack has a particular behaviour when dealing with expressions inside require statements, that hinders my attempts to load modules in the way described above. In particular, when using an expression inside require it
tries to include all files that are possible with your expression
The net effect is a huge pile of error messages when I try to run Webpack with the above code.
Though the linked resources suggest to explicitly declare the path of the JavaScript files to include, what I fail to get is how to do the same thing when I cannot, or don't want to, pass a precise path to require, but rather use the automatically resolved modules, as shown.
Thanks all
EDIT:
I still don't known how to use expressions to load those scripts, however, I designed a workaround. Basically, the idea is to explicitly write the require('script') inside a callback function, and then dinamically call that function when it's time. More precisely, I prepared a configuration file like this:
// config.js
'use strict';
module.exports = {
'lib': {
'jquery': {
'object': 'jQuery',
'dev': function() { require('script!jquery'); },
'dist': function() { return require('jquery-cdn'); },
'cdn': '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'
},
'handlebars': {
// ...
}
}
};
Inside my main code I, then, define an array of resources to load, like:
var config = require('./config.js');
var resources = [ config.lib.jquery, config.lib.handlebars, ... ];
And then when I have to load the development version, or the distribution version, I dinamically call:
// Inside some kind of cycle
// resource = resources[index]
try {
window[resource.object] = resource.dist();
} catch (e) {
console.log('Cannot load ' + resource.object + ' from CDN. Loading local version...');
resource.dev();
}
Here there's a more complete example of this in action.
I have a strange behaviour in require, that I dont know how to avoid (or maybe I have my basics wrong?).
Consider the following code:
define (require) ->
potoo = require "potoo"
service = require "communication.data"
downloadIfNeeded = ->
# ...
service.download()
new potoo.App
pageContainer: potoo.UI.NGStylePage
userRequired: true
stdRoute: "overview"
onLogin: downloadIfNeeded
This is not going to work, because 'communication.data' itself requires 'app' (the code shown). so we obviously have a circular dependency. That fails with a 'Uncaught Error: Module name "app" has not been loaded yet for context: _'
Since the downloadIfNeeded function doesn't get called until after the user actually clicks something, I figured, that something like the following should work:
define (require) ->
potoo = require "potoo"
downloadIfNeeded = ->
service = require "communication.data"
service.download()
...
But that actually throws the same error as above. To make it work, i have to use a little hack. I alias the require function with some other name:
define (require) ->
potoo = require "potoo"
reqs = require
downloadIfNeeded = ->
service = reqs "communication.data"
service.download()
...
Is this the best way to do so? Or would you recommend the CommonJS Style (module.export) that is also supported by requirejs.
I've done a test here and was able to find a solution. What you have is equivalent to this JavaScript:
define(function (require) {
This is enough to be able to use the (fake) synchronous form of require. However, RequireJS will give you the error you got when you try to use a synchronous require and you have circular dependencies. What you need is this:
define(function (require, exports, module) {
This is so that your module uses exports to export its values and consequently RequireJS has an object that can be updated when the module has finished initialized.
Using RequireJS I'm building an app which make extensive use of widgets. For each widget I have at least 3 separate files:
request.js containing code for setting up request/response handlers to request a widget in another part of my application
controller.js containing handling between model and view
view.js containing handling between user and controller
Module definition in request.js:
define(['common/view/widget/entity/term/list/table/controller'],
function(WidgetController) { ... });
Module definition in controller.js:
define(['common/view/widget/entity/term/list/table/view'],
function(WidgetView) { ... });
Module definition of view.js is:
define(['module','require'],function(module,require) {
'use strict';
var WidgetView = <constructor definition>;
return WidgetView;
});
I have lots of these little situations as above in the case of widgets I have developed. What I dislike is using the full path every time when a module is requiring another module and both are located in the same folder. I'd like to simply specify as follows (assuming we have a RequireJS plugin which solves this for us):
define(['currentfolder!controller'],
function(WidgetController) { ... });
For this, I have written a small plugin, as I couldn't find it on the web:
define({
load: function (name, parentRequire, onload, config) {
var path = parentRequire.toUrl('.').substring(config.baseUrl.length) + '/' + name;
parentRequire([path], function (value) {
onload(value);
});
}
});
As you might notice, in its basic form it looks like the example of the RequireJS plugins documentation.
Now in some cases, the above works fine (e.g. from the request.js to the controller.js), but in other cases a load timeout occurs (from controller.js to view.js). When I look at the paths which are generated, all are proper RequireJS paths. Looking at the load timeouts, the following is logged:
Timestamp: 13-09-13 17:27:10
Error: Error: Load timeout for modules: currentfolder!view_unnormalized2,currentfolder!view
http://requirejs.org/docs/errors.html#timeout
Source File: http://localhost/app/vendor/requirejs/require.js?msv15z
Line: 159
The above log was from a test I did with only loading the view.js from controller.js using currentfolder!view in the list of modules in the define statement. Since I only requested currentfolder!view once, I'm confused as to why I both see currentfolder!view_unnormalized2 and currentfolder!view in the message.
Any idea as to why this might be happening?
My answer may not answer your primary questions, but it will help you achieve what you're trying to do with your plugin.
In fact, Require.js support relative paths for requiring modules when using CommonJS style. Like so:
define(function( require, exports, module ) {
var relativeModule = require("./subfolder/module");
module.exports = function() {
console.log( relativeModule );
};
});
Let's suppose I can access the following code:
http://localhost/web/src/js/myApp.js
Now I want to load myApp.js using requirejs from the javascript command line mode.
I did try the following but it does not work. Any ideas?
requirejs.config({
baseUrl: "http://localhost/web/src/"
});
require("js/myApp"); // Error: Module name 'js/myApp' has not been loaded yet for context: _ http://requirejs.org/docs/errors.html#notloaded
That's because require('FILENAME') is used for loading already loaded files...i don't know what's the purpose behind it. You should use:
require(['module'], function(mod) {
... do some work ...
// later, maybe if you want this (although, i don't understand why)
require('module', function(m) {
... do some work with m - the new (or old?) module!
})
});