RequireJS: Dynamic dependencies within nested require of a module - javascript

Suppose there is a function that returns an array containing dynamic dependencies.
Then within a module B these dependencies are used. Another module A in turn uses module B.
A.js
define([B], function(moduleB){
moduleB.m();
})
B.js:
define([ dep1, dep2 ], function( dep1, dep2 ) {
var dyndeps = dep2.getDynDeps();
var moduleB = {}
require(dyndeps, function() {
moduleB.m = function() { ... };
})
return moduleB;
});
The problem with this approach is, that the inner require is executed asynchronously, so the method m is not available in time.

Since B.m is provided by a dynamic dependency, B should provide an interface for waiting on it to become available. There are a number of plugins to allow that, e.g. rq (using Q promises), promise (using jquery, Q, RSVP or ES6 promises), promiseme (self-contained?).
Using one of those, B would not return moduleB, but a promise. The nested require call would resolve the promise with complete moduleB. A would require <PLUGIN>!B. E.g. using promise and jquery:
// A.js
define(["promise!B"], function(moduleB){
// B is complete now
moduleB.m();
})
// B.js
define([ "dep1", "dep2", "jquery" ], function( dep1, dep2, $ ) {
var dyndeps = dep2.getDynDeps();
var moduleB = {};
var loaded = new $.Deferred();
require(dyndeps, function() {
moduleB.m = function() { ... };
loaded.resolve(moduleB);
})
return loaded.promise();
});
The only remaining problem with this approach is that the client code (A.js) needs to know to depend on B in a special way. A better solution would be to have B hide its dynamic nature like:
// A.js
define(["B"], function(moduleB){
moduleB.m();
})
// B.js
define([ "promise!dynamicB" ], function( moduleB ) {
return moduleB;
});
// still inside B.js define a "private" named module:
define("dynamicB", ["dep1", "dep2", "jquery"], function() {
var dyndeps = dep2.getDynDeps();
var loaded = new $.Deferred();
var moduleB = {};
require(dyndeps, function() {
moduleB.m = function() { ... };
loaded.resolve(moduleB);
})
return loaded.promise();
});
Now B can be used just as any other module.

Related

protractor calling an exported function within the same module

I'm newer to using Protractor for automation, so forgive me if this ends up being a dumb question. I have a helper.js module with a bunch of functions that I or other team members can use. One of the functions from helper.js needs to call to one of the existing functions in the module.
Is this possible? I have tried several different ways to do this and so far none have worked other than to break the helper functions into a separate js file that I need to call to.
Example:
helper.js:
module.exports = {
newbrowsertab: function(){
<code>
},
anotherfunction: function(){
<code>
<call to newbrowsertab();>
<code>
},
anotherfunction2: function(){
<code>
}
};
In the call to the newbrowsertab function, I've tried:
module.newbrowsertab();
this.newbrowsertab();
self.newbrowsertab();
You could use Prototypal inheritance then:
// helper.js functions
// create object
var Util = function() {};
// extend object
Util.prototype.enterPassword = function() {
// code
};
// extend object
Util.prototype.clickLogin = function() {
// code
};
// use `this` to call functions in same module
Util.prototype.fullLogin = function() { // extend object
this.enterPassword();
this.clickLogin();
};
module.exports = new Util();
Then in your test file:
var Util = require('./path/to/helper.js);
Util.fullLogin();
etc...
Expanding on the prototypal convention.
Any functions that are only helpers for other exported functions could be named with an underscore and declared to be executed later.
function _helperFunction(){
// do something
// return something
}
var exposedFunction = function() {
// do something
var x = _helperFunction();
// Do something else
}
module.exports = {
exposedFunction : exposedFunction
};

Node.js double call to require()

//lib.js
var opt = 0
exports.set = function(arg) {
opt = arg
}
exports.prn = function() {
console.log(opt)
}
///prog.js
var lib = require('./lib')
var lib2 = require('./lib')
lib.set(222)
lib2.set(333)
lib.prn()
lib2.prn()
prog.js will output:
333
333
but I need it to output:
222
333
In ohter words, opt must be unique to variable lib and to variable lib2. How to achieve that?
That's because normally nodejs caches its modules which are got via require. You may use the following helper:
// RequireUncached.js
module.exports = function(module) {
delete require.cache[require.resolve(module)]
return require(module);
}
and the usage of the helper:
var requireUncached = require('RequireUncached.js');
requireUncached("./lib");
Have in mind that this approach is considered as bad practice and should not be used. I'll suggest to wrap your logic into a function, require the module and call the function. So, every time you get a new instance.
require will not load scripts multiple times, but always yield the same instance.
If you need different environments, make your module a constructor function that allows to be instantiated multiple times. Store opt on each object for that instead of in the (global) module scope.
// lib.js
module.exports = function constr() {
var opt = 0
this.set = function(arg) {
opt = arg
};
this.print = function() {
console.log(opt)
};
};
// prog.js
var lib = require('./lib'),
inst1 = new lib(),
inst2 = new lib();
/* or short:
var inst1 = new require('./lib')(),
inst2 = new require('./lib')(); */
inst1.set(222)
inst2.set(333)
inst1.print()
inst2.print()
The way the NodeJS module system works, the output is correct and your expectations contradict the design principle here.
Each module is loaded once and only once, and subsequent calls to require simply return the reference to the pre-existing module.
Maybe what you need to do is create a class you can create one or more instances of instead of using module-level globals.
Adding to Bergi's answer, You may also try it like
// prog.js
var lib = require('./lib')(),
lib2 = require('./lib')();
lib.set(222)
lib2.set(333)
lib.print()
lib2.print()
// lib.js
module.exports = function constr() {
var opt = 0
return { set : function(arg) {
opt = arg
},
print : function() {
console.log(opt)
}
}
};
Add this line as first line of your lib.js
delete require.cache[__filename]
now your module becomes in a separate namespace each time you require it.

How to solve circular dependency in Require.js?

Basically, the idea is that "sub" module creates an object, and that object should be part of a utilities library which is the "main" module. However, the "sub" object depends on utilities from "main":
// Main module
define(['sub'], function(sub) {
var utils = {
utilityMain: function () {
// ...
};
// ...
};
tools.subModule = sub;
return tools;
});
// Sub module
define(['main'], function(main) {
return new (function () {
// Singleton object using functions in main module
var somestuff = function () {
main.utilityMain();
// etc
};
})();
});
How can I achieve this with require.js without creating a black hole that would swallow the whole planet?
Thank you very much.
There are a few things suggested in the docs:
b can fetch a later after modules have been defined by using the require() method (be sure to specify require as a dependency so the right context is used to look up a)
e.g.:
// Sub module
define(['require'], function(require) {
return new (function () {
// Singleton object using functions in main module
var somestuff = function () {
require('main').utilityMain();
// etc
};
})();
});
or
you could instead use exports to create an empty object for the module that is available immediately for reference by other modules
e.g.:
// Main module
define(['sub', 'exports'], function(sub, exports) {
exports.utilityMain: function () {
// ...
};
exports.subModule = sub.sub;
});
// Sub module
define(['main', 'exports'], function(main, exports) {
exports.sub = new (function () {
// Singleton object using functions in main module
var somestuff = function () {
main.utilityMain();
// etc
};
})();
});
and
Circular dependencies are rare, and usually a sign that you might want to rethink the design

Circular Dependencies in modules using requireJs

Reading the requireJs documentation,
in order to fix the Circular Dependencies, is suggested to use exports to create an empty object for the module that is available immediately for reference by other modules.
I try this code but it seems to do not work. What is wrong?
P.S.:
read the comments for seeing the output,
especially the B module inside setTimeout call.
// A module
define([
'b'
], function (b) {
console.log('B:', b); // B, Object
var A = {
boo: 1
};
return A;
});
// B module
define([
'a',
'exports'
], function (a, exports) {
console.log('A:', a); // A, undefined (as I was expecting)
exports.A = function () {
return a;
}
var B = {
bar: 1
};
setTimeout(function () {
console.log('exports.A', exports.A()); // exports.A undefined
// I would like to access the A object
// which is defined in A module
}, 500);
return B;
});
// main.js
(function () {
define([
'a'
], function () {
});
}());
You should be able to use the synchronous version of require() in your B module to access the "A" module:
// B module
define([
'a',
'exports'
], function (a, exports) {
console.log('A:', a); // A, undefined (as I was expecting)
exports.A = function () {
return require('a');
}
...
});
I often have circular issues using AMD modules to build an application core that both stands up many modules and contains config or other useful objects for those modules to use.
I did some experimenting today and this seems to work pretty well.
define(['exports', 'underscore', './config', './mediator'],
function (exports, _, Backbone, config, Mediator){
Core = /* ... */
// Publicize a core 'singleton' so that it's dependencies can access it, and so can modules that define it as a dependency themselves.
core = new Core()
exports.core = core //publicize it in a way that supports circularity
return core // And also publicize it normally
}
)
The objects are both '===' equal to each other, so this seems very promising.
EDIT:
The above method doesn't work when optimized. Here's another method that may (untested):
https://github.com/requirejs/example-multipage/blob/master/www/js/app/main1.js#L2
define(function (require) {
var $ = require('jquery'),
lib = require('./lib'),
Core;
Core = /* ... */
return new Core()
});
One option would be not to return the module itself, but a function that instantiates the module (in this example it would a constructor as defined in typescript, at the bottom is the generated js code -note that interfaces do not generate .js code)
File IA.ts
/// <reference path="IB.ts" />
interface IA{
funcA();
_classB : IB;
}
File IB.ts
/// <reference path="IA.ts" />
interface IB{
funcB();
_classA : IA;
}
File ClassA.ts
/// <reference path="IA.ts" />
/// <reference path="IB.ts" />
export class ClassA implements IA
{
_classB : IB = null;
constructor(classB : IB)
{
this._classB = classB;
if (classB){
this._classB._classA = this;
}
return this;
}
funcA(){
console.log('I am ClassA');
}
}
File ClassB.ts
/// <reference path="IA.ts" />
/// <reference path="IB.ts" />
export class ClassB implements IB
{
_classA : IA = null;
constructor(classA : IA)
{
this._classA = classA;
if (classA){
this._classA._classB = this;
}
return this;
}
funcB(){
console.log('I am ClassB');
}
}
File MainTest.ts
/// <reference path="../../def/require.d.ts" />
/// <reference path="IA.ts" />
/// <reference path="IB.ts" />
define(['ClassA', 'ClassB'],
function (classA, classB)
{
var aa : IA = new classA.ClassA();
var bb : IB = new classB.ClassB(aa);
bb.funcB();
aa._classB.funcB();
bb._classA.funcA();
aa.funcA();
});
And the generated js code:
File ClassA.js
define(["require", "exports"], function(require, exports) {
var ClassA = (function () {
function ClassA(classB) {
this._classB = null;
this._classB = classB;
if (classB) {
this._classB._classA = this;
}
return this;
}
ClassA.prototype.funcA = function () {
console.log('I am ClassA');
};
return ClassA;
})();
exports.ClassA = ClassA;
});
File ClassB.js
define(["require", "exports"], function(require, exports) {
var ClassB = (function () {
function ClassB(classA) {
this._classA = null;
this._classA = classA;
if (classA) {
this._classA._classB = this;
}
return this;
}
ClassB.prototype.funcB = function () {
console.log('I am ClassB');
};
return ClassB;
})();
exports.ClassB = ClassB;
});
File MainTest.js
define(['ClassA', 'ClassB'], function (classA, classB) {
var aa = new classA.ClassA();
var bb = new classB.ClassB(aa);
bb.funcB();
aa._classB.funcB();
bb._classA.funcA();
aa.funcA();
});
finally, the output will be:
I am ClassB
I am ClassB
I am ClassA
I am ClassA

I want to return a function and have it evaluated in the calling module

I'm not sure why this isn't working. I wrapped my function in an anonymous function with the belief that it wouldn't get evaluated until it was called elsewhere. But I'm getting an error about "dropchart" not being defined, so it's getting evaluated within this module.
define(function() {
var stage = {
before: {
createCanvas: function() {
return function() {
before(function(done) {
this.canvas = new dropchart.Canvas({
canvas: argsFor.canvas(),
data: argsFor.data()
});
done();
});
};
}
}
};
return stage;
});
This is how it is called from the other module:
define(['jquery', 'dropchart', 'argsFor', 'stage'],
function($, dropchart, argsFor, stage) {
var should = chai.should();
var xAxisSpec = {
run: function() {
describe('xAxis', function() {
stage.before.createCanvas();
...
The stage module has the argsFor and dropchart dependencies, not the calling module.
The calling module cannot somehow make those available for stage module, unless you pass them as arguments in stage.before.createCanvas or you put them to global scope which defeats the whole point of require.js

Categories

Resources