Best practice to inject modules in angularJS using browserify - javascript

I'm trying to simplify my angular application with gulp and browserify. Unfortunately I'm struggling with the concept of require and exports mixed with angulars dependency injection (DI). I have to change a lot of files in order to get the browserify running so I want ro get some things clear before I start.
For example, I have a module moduleAB that contains two factories, each defining a class. FactoryA creates classA and factoryB creates classB. classB inherits from classA. So in my code I have something like:
angular.module("moduleAB", [])
.factory("factoryA", ["$window", function(wndw) {
return function classA (a, b) {
this.a = a;
this.b = b;
};
}])
.factory("factoryB", ["factoryA", function(classA) {
var classB = function (a, b) {
classA.call(this, a, b);
};
classB.prototype = Object.create(classA.prototype);
classB.prototype.constructor = classB;
return classB;
}]);
Now I read that for perfect usage of browserify I have to split my modules into separate files and use an index.js to require the parts of this module:
var angular = require("angular");
module.exports = angular.module("moduleAB", [])
.factory("factoryA", require("./factoryA"))
.factory("factoryB", require("./factoryB"));
So far, so good. Now I need files for factory A and B. But what's the best way to implement these and preserve DI? Should I write something like (factoryA.js):
module.exports = ["$window", function(wndw) {
return function classA (a, b) {
//...
};
}];
And (factoryB.js):
module.exports = ["factoryA", function(factoryA) {
//...
}];
Or is it better to do (factoryB.js):
var factoryA = require("./factoryA");
module.exports = [function() {
//...
}];
Or (factoryB.js):
module.exports = [require("./factoryA"), function(factoryA) {
//...
}];
It's important that after minification DI still works :)

Related

JavaScript NodeJs - TypeError X is not a constructor [duplicate]

I've been working with nodejs lately and still getting to grips with the module system, so apologies if this is an obvious question. I want code roughly like the below:
a.js (the main file run with node)
var ClassB = require("./b");
var ClassA = function() {
this.thing = new ClassB();
this.property = 5;
}
var a = new ClassA();
module.exports = a;
b.js
var a = require("./a");
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
util.log(a.property);
}
module.exports = ClassB;
My problem seems to be that I can't access the instance of ClassA from within an instance of ClassB.
Is there any correct / better way to structure modules to achieve what I want?
Is there a better way to share variables across modules?
Try to set properties on module.exports, instead of replacing it completely. E.g., module.exports.instance = new ClassA() in a.js, module.exports.ClassB = ClassB in b.js. When you make circular module dependencies, the requiring module will get a reference to an incomplete module.exports from the required module, which you can add other properties latter on, but when you set the entire module.exports, you actually create a new object which the requiring module has no way to access.
While node.js does allow circular require dependencies, as you've found it can be pretty messy and you're probably better off restructuring your code to not need it. Maybe create a third class that uses the other two to accomplish what you need.
[EDIT] it's not 2015 and most libraries (i.e. express) have made updates with better patterns so circular dependencies are no longer necessary. I recommend simply not using them.
I know I'm digging up an old answer here...
The issue here is that module.exports is defined after you require ClassB.
(which JohnnyHK's link shows)
Circular dependencies work great in Node, they're just defined synchronously.
When used properly, they actually solve a lot of common node issues (like accessing express.js app from other files)
Just make sure your necessary exports are defined before you require a file with a circular dependency.
This will break:
var ClassA = function(){};
var ClassB = require('classB'); //will require ClassA, which has no exports yet
module.exports = ClassA;
This will work:
var ClassA = module.exports = function(){};
var ClassB = require('classB');
I use this pattern all the time for accessing the express.js app in other files:
var express = require('express');
var app = module.exports = express();
// load in other dependencies, which can now require this file and use app
Sometimes it is really artificial to introduce a third class (as JohnnyHK advises), so in addition to Ianzz:
If you do want to replace the module.exports, for example if you're creating a class (like the b.js file in the above example), this is possible as well, just make sure that in the file that is starting the circular require, the 'module.exports = ...' statement happens before the require statement.
a.js (the main file run with node)
var ClassB = require("./b");
var ClassA = function() {
this.thing = new ClassB();
this.property = 5;
}
var a = new ClassA();
module.exports = a;
b.js
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
util.log(a.property);
}
module.exports = ClassB;
var a = require("./a"); // <------ this is the only necessary change
The solution is to 'forward declare' your exports object before requiring any other controller. So if you structure all your modules like this and you won't run into any issues like that:
// Module exports forward declaration:
module.exports = {
};
// Controllers:
var other_module = require('./other_module');
// Functions:
var foo = function () {
};
// Module exports injects:
module.exports.foo = foo;
What about lazy requiring only when you need to? So your b.js looks as follows
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
var a = require("./a"); //a.js has finished by now
util.log(a.property);
}
module.exports = ClassB;
Of course it is good practice to put all require statements on top of the file. But there are occasions, where I forgive myself for picking something out of an otherwise unrelated module. Call it a hack, but sometimes this is better than introducing a further dependency, or adding an extra module or adding new structures (EventEmitter, etc)
You can solve this easily: just export your data before you require anything else in modules where you use module.exports:
classA.js
class ClassA {
constructor(){
ClassB.someMethod();
ClassB.anotherMethod();
};
static someMethod () {
console.log( 'Class A Doing someMethod' );
};
static anotherMethod () {
console.log( 'Class A Doing anotherMethod' );
};
};
module.exports = ClassA;
var ClassB = require( "./classB.js" );
let classX = new ClassA();
classB.js
class ClassB {
constructor(){
ClassA.someMethod();
ClassA.anotherMethod();
};
static someMethod () {
console.log( 'Class B Doing someMethod' );
};
static anotherMethod () {
console.log( 'Class A Doing anotherMethod' );
};
};
module.exports = ClassB;
var ClassA = require( "./classA.js" );
let classX = new ClassB();
A solution which require minimal change is extending module.exports instead of overriding it.
a.js - app entry point and module which use method do from b.js*
_ = require('underscore'); //underscore provides extend() for shallow extend
b = require('./b'); //module `a` uses module `b`
_.extend(module.exports, {
do: function () {
console.log('doing a');
}
});
b.do();//call `b.do()` which in turn will circularly call `a.do()`
b.js - module which use method do from a.js
_ = require('underscore');
a = require('./a');
_.extend(module.exports, {
do: function(){
console.log('doing b');
a.do();//Call `b.do()` from `a.do()` when `a` just initalized
}
})
It will work and produce:
doing b
doing a
While this code will not work:
a.js
b = require('./b');
module.exports = {
do: function () {
console.log('doing a');
}
};
b.do();
b.js
a = require('./a');
module.exports = {
do: function () {
console.log('doing b');
}
};
a.do();
Output:
node a.js
b.js:7
a.do();
^
TypeError: a.do is not a function
The important thing is not to re-assign the module.exports object that you have been given, because that object may have already been given to other modules in the cycle! Just assign properties inside module.exports and other modules will see them appear.
So a simple solution is:
module.exports.firstMember = ___;
module.exports.secondMember = ___;
The only real downside is the need to repeat module.exports. many times.
Similar to lanzz and setec's answers, I have been using the following pattern, which feels more declarative:
module.exports = Object.assign(module.exports, {
firstMember: ___,
secondMember: ___,
});
The Object.assign() copies the members into the exports object that has already been given to other modules.
The = assignment is logically redundant, since it is just setting module.exports to itself, but I am using it because it helps my IDE (WebStorm) to recognise that firstMember is a property of this module, so "Go To -> Declaration" (Cmd-B) and other tooling will work from other files.
This pattern is not very pretty, so I only use it when a cyclic dependency issue needs to be resolved.
It is fairly well suited to the reveal pattern, because you can easily add and remove exports from the object, especially when using ES6's property shorthand.
Object.assign(module.exports, {
firstMember,
//secondMember,
});
the extremely simple solution is often:
usually you'd have the require at the top of the file ...
var script = require('./script')
function stuff() {
script.farfunction()
}
instead, just require it "in the function"
function stuff() {
var _script = require('./script')
_script.farfunction()
}
An other method I've seen people do is exporting at the first line and saving it as a local variable like this:
let self = module.exports = {};
const a = require('./a');
// Exporting the necessary functions
self.func = function() { ... }
I tend to use this method, do you know about any downsides of it?
TL;DR
Just use exports.someMember = someMember instead of module.exports = { // new object }.
Extended Answer
After reading lanzz's response I could finally figure it out what is happening here, so I'll give my two cents on the subject, extending his answer.
Let's see this example:
a.js
console.log("a starting");
console.log("a requires b");
const b = require("./b");
console.log("a gets b =", b);
function functionA() {
console.log("function a");
}
console.log("a done");
exports.functionA = functionA;
b.js
console.log("b starting");
console.log("b requires a");
const a = require("./a");
console.log("b gets a =", a);
function functionB() {
console.log("On b, a =", a)
}
console.log("b done");
exports.functionB = functionB;
main.js
const a = require("./a");
const b = require("./b");
b.functionB()
Output
a starting
a requires b
b starting
b requires a
b gets a = {}
b done
a gets b = { functionB: [Function: functionB] }
a done
On b, a = { functionA: [Function: functionA] }
Here we can see that at first b receives an empty object as a, and then once a is fully loaded, that reference is updated through exports.functionA = functionA. If you instead replace the entire module with another object, through module.exports, then b will lose the reference from a, since it will point out to the same empty object from the beginning, instead of pointing to the new one.
So if you export a like this: module.exports = { functionA: functionA }, then the output will be:
a starting
a requires b
b starting
b requires a
b gets a = {}
b done
a gets b = { functionB: [Function: functionB] }
a done
On b, a = {} // same empty object
Actually I ended up requiring my dependency with
var a = null;
process.nextTick(()=>a=require("./a")); //Circular reference!
not pretty, but it works. It is more understandable and honest than changing b.js (for example only augmenting modules.export), which otherwise is perfect as is.
Here is a quick workaround that I've found use full.
On file 'a.js'
let B;
class A{
constructor(){
process.nextTick(()=>{
B = require('./b')
})
}
}
module.exports = new A();
On the file 'b.js' write the following
let A;
class B{
constructor(){
process.nextTick(()=>{
A = require('./a')
})
}
}
module.exports = new B();
This way on the next iteration of the event loop classes will be defined correctly and those require statements will work as expected.
One way to avoid it is to don't require one file in other just pass it as an argument to a function what ever you need in an another file.
By this way circular dependency will never arise.
If you just can't eliminate circular dependencies (e.g useraccount <---> userlogin), there's one more option...
Its as simple as using setTimeout()
//useraccount.js
let UserLogin = {};
setTimeout(()=>UserLogin=require('./userlogin.js'), 10);
class UserAccount{
getLogin(){
return new UserLogin(this.email);
}
}
//userlogin.js
let UserAccount ={};
setTimeout(()=>UserAccount=require('./useraccount.js'), 15);
class UserLogin{
getUser(){
return new User(this.token);
}
}

Creating an instance of multiple javascript modules

This related to javascript code. My application has many sub applications that are sometimes used more then once on a page. An example would be an application that allows the user to search for some data and displaying the search results. This application my be used in multiple places on a page to search for different types of data.
Each sub application typically includes many javascript modules each in a separate file. I have experienced with many different module patterns to try to create a separate instance of multiple modules/files but with no success. There is much advice online how to create multiple instances of objects, using factory pattern etc but I have not been able to make it work with the name space structure and module pattern my application. See example below.
The question is how can you create multiple independent instances of SubAppA including all its sub modules.
(New file)
var MainApp = MainApp || {};
MainApp.SubAppA = MainApp.SubAppA || {};
MainApp.SubAppA.Config = (function () {
function A () { ... };
function B () { ... };
return {
A : A,
B : B
}
})();
(New file)
var MainApp = MainApp || {};
MainApp.SubAppA = MainApp.SubAppA || {};
MainApp.SubAppA.GetData = (function () {
function A () { ... };
function B () { ... };
return {
A : A,
B : B
}
})();
(New file)
var MainApp = MainApp || {};
MainApp.SubAppA = MainApp.SubAppA || {};
MainApp.SubAppA.DisplayData = (function () {
etc.....
Many thanks in advance
--- Additional information after solution proposed by MikeM -----
Thanks MikeM, you answer gave me a better understanding but when trying to implement it using my existing name space structure, I can't get the modules to communicate with each other. I tried the following:
//Solution $S.AS - New file
var $S = $S || {};
$S.AS = $S.AS || {};
$S.AS.DataStore = function () {
var _SomeVar = "Default";
function SetVar (Data) {
_SomeVar = Data;
};
function GetVar () {
return _SomeVar;
};
return {
SetVar : SetVar,
GetVar : GetVar
}
};
//Solution $S.AS - New file
var $S = $S || {};
$S.AS = $S.AS || {};
$S.AS.ManageData = function () {
function StoreData (Data) {
console.log($S.AS.DataStore); //outputs f ()
//Does now work since DataStore is now a function
//$S.AS.DataStore.SetVar(Data);
$S.AS.DataStore().SetVar(Data);
};
function DisplayData () {
//Does now work since DataStore is now a function
//var SomeVar = $S.AS.DataStore.GetVar();
//Does not work, still outputs "Default"
var SomeVar = $S.AS.DataStore().GetVar();
console.log(SomeVar);
};
return {
StoreData : StoreData,
DisplayData : DisplayData
}
};
//Solution $S.AS - New file - The contructor function for AS
var MainApp = MainApp || {};
MainApp.S = MainApp.S || {};
MainApp.S.AS = MainApp.S.AS || {};
MainApp.S.AS = function () {
this.DataStore = $S.AS.DataStore();
this.ManageData = $S.AS.ManageData();
//additional modules
};
//Main/Page specific code - creating the different instances
MainApp.S.AS_1 = new MainApp.S.AS();
MainApp.S.AS_2 = new MainApp.S.AS();
//Attemps to store and retrieve data
//Stores AAA in the DataStore module
MainApp.S.AS_1.ManageData.StoreData("AAA");
//Stores BBB in the DataStore module
MainApp.S.AS_2.ManageData.StoreData("BBB");
//Not working, ouputs: "Default" (Desired result is "AAA")
MainApp.S.AS_1.ManageData.DisplayData();
//Not working, ouputs: "Default" (Desired result is "BBB");
MainApp.S.AS_2.ManageData.DisplayData();
I think I understand why "Default" is output (the call is made to the original variable stored at page load) but not how to fix it.
For context, I have a custom php script that concatenates all the JS files required for a page and then adds them as a single tag to the page. I thought this would speed up script loading, in particular since most of my pages will have 50+ JS files/modules. A typical Name space structure for a page will look as follows (but with a lot more modules):
MainApp = {
//Page specific or utility modules
ModuleA : [ func / module ],
ModuleB : [ func / module ],
ModuleC : [ func / module ],
ModuleD : [ func / module ],
//Resulable applications consisting of multiple modules
SubAppA : {
ModuleA : [ func / module ],
ModuleB : [ func / module ],
ModuleC : [ func / module ],
ModuleD : [ func / module ],
},
SubAppB : {
ModuleA : [ func / module ],
ModuleB : [ func / module ],
ModuleC : [ func / module ],
ModuleD : [ func / module ],
}
}
I was hoping that I can somehow preserver this structure to avoid the risk of conflicting module names. I am happy to change the structure of the modules themselves (e.g. from IIFE to something else) to get an solution to the question.
Thanks
Thanks MikeM, it is now working, very helpful! Yes I am aware of that I need to look at ES modules closer. I learned to code recently to test an idea after working in a completely different field for 17 years so some shortcuts had to be made ...
Here is a write up of my implementation step by step in case it helps someone else that is not too familiar with Javascript modules.
The objectives of the question were to:
Enable multiple instances of an application to exist on a page where each application consists of multiple modules
Enable the modules to call methods in other modules
Make it easy to instantiate (create a new version) of the application
Some things to consider in relation to below solution:
Rather than static calls to methods in other module (e.g. ReuseApp.App1.Display.DisplayData(Data) each module stores an internal reference of the top object of the newly created instance of the application (e.g. _App.Display.DisplayData(Data).
Module are created without the immediately evoked feature (i.e. no IIFE pattern).
A construction function referencing all required module are required. This function will send the newly created object (this) into each module e.g. this.Config = ReuseApps.App1.Config(this);
Each module to take this reference as a parameter (App) and store it within the module (_App). _App will be used when calling other module methods.
Step by step by step guide:
STEP A: Create modules using the following pattern (disregard multi level namespaces if not needed):
//Separate file e.g. Config.js
const ReuseApps = ReuseApps || {};
ReuseApps.App1 = ReuseApps.App1 || {};
ReuseApps.App1.Config = function (App) {
let _App; //Used to call other module methods
let _Settings = {};
function Init (Settings) {
_Settings = Settings;
//Configure app e.g. store element refs, add event handlers etc
var Data = GetDataFromSomeWhere();
//Call another module using the _App reference
_App.Display.DisplayData(Data);
}
_App = App;
Return {
Init : Init
}
}
//Separate file e.g. Display.js
const ReuseApps = ReuseApps || {};
ReuseApps.App1 = ReuseApps.App1 || {};
ReuseApps.App1.Display = function (App) {
let _App; //Used to call other module methods
function DisplayData (Data) {
//Display Data in DOM
}
_App = App;
return {
DisplayData : DisplayData
}
}
STEP B: Create the construction function required to create a new instance of application
//can be in separate file e.g. app1_create.js
function App1Create () {
this.Config = ReuseApps.App1.Config(this);
this.Display = ReuseApps.App1.Display(this);
//etc more modules …
}
STEP C: Creating a separate instance of above application in the main code
//Create new instance using constructur function
//(Assumes the MainApp namespace exists already)
MainApp.ViewDataList = new App1Create();
//If application needs to be initiated
var Settings = { some settings };
MainApp.ViewDataList.Config.Init(Settings);
A simple example of one way of creating "multiple independent instances of SubAppA including all its sub modules", where the modules are defined in multiple files:
// test.js
import { MainApp } from './mainApp.js';
import { SubApp } from './subApp.js';
MainApp.SubAppA = new SubApp();
console.log(MainApp.SubAppA.Config.A()); // 1
MainApp.SubAppB = new SubApp();
console.log(MainApp.SubAppB.Config.B()); // -1
// subApp.js
import { config } from './config.js';
import { getData } from './getData.js';
export function SubApp() {
this.Config = config();
this.GetData = getData();
}
// config.js
export function config() {
let counter = 0;
function A() { return ++counter };
function B() { return --counter };
return {
A: A,
B: B
}
}
As a single file:
const MainApp = {};
function SubApp() {
this.Config = config();
this.GetData = getData();
}
function config() {
let counter = 0;
function A() { return ++counter };
function B() { return --counter };
return {
A: A,
B: B
}
}
function getData() {
let counter = 0;
function A() { return ++counter };
function B() { return --counter };
return {
A: A,
B: B
}
}
MainApp.SubAppA = new SubApp();
console.log(MainApp.SubAppA.Config.A()); // 1
console.log(MainApp.SubAppA.GetData.A()); // 1
console.log(MainApp.SubAppA.Config.B()); // 0
MainApp.SubAppB = new SubApp();
console.log(MainApp.SubAppB.Config.B()); // -1
console.log(MainApp.SubAppB.GetData.B()); // -1
console.log(MainApp.SubAppB.Config.A()); // 0
The important difference with your own code is that I have replaced the Immediately-Invoked Function Expressions (IIFE) with normal functions that create closures every time a SubApp is created.
Added in response to your edit:
For the code you added in your edit to work, you need to make sure that you pass a reference to the parent object when you create a new ManageData object:
$S.AS.ManageData = function (owner) {
function StoreData (Data) {
owner.DataStore.SetVar(Data);
};
function DisplayData () {
var SomeVar = owner.DataStore.GetVar();
console.log(SomeVar);
};
return {
StoreData : StoreData,
DisplayData : DisplayData
}
};
// ...
MainApp.S.AS = function () {
this.DataStore = $S.AS.DataStore();
this.ManageData = $S.AS.ManageData(this);
};
I encourage you to use ES modules to structure your code and avoid naming collisions. A single file can be created from a module bundler such as roll-up.js.

Does requiring a module that requires the same file cause issues in Node.js? [duplicate]

I've been working with nodejs lately and still getting to grips with the module system, so apologies if this is an obvious question. I want code roughly like the below:
a.js (the main file run with node)
var ClassB = require("./b");
var ClassA = function() {
this.thing = new ClassB();
this.property = 5;
}
var a = new ClassA();
module.exports = a;
b.js
var a = require("./a");
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
util.log(a.property);
}
module.exports = ClassB;
My problem seems to be that I can't access the instance of ClassA from within an instance of ClassB.
Is there any correct / better way to structure modules to achieve what I want?
Is there a better way to share variables across modules?
Try to set properties on module.exports, instead of replacing it completely. E.g., module.exports.instance = new ClassA() in a.js, module.exports.ClassB = ClassB in b.js. When you make circular module dependencies, the requiring module will get a reference to an incomplete module.exports from the required module, which you can add other properties latter on, but when you set the entire module.exports, you actually create a new object which the requiring module has no way to access.
While node.js does allow circular require dependencies, as you've found it can be pretty messy and you're probably better off restructuring your code to not need it. Maybe create a third class that uses the other two to accomplish what you need.
[EDIT] it's not 2015 and most libraries (i.e. express) have made updates with better patterns so circular dependencies are no longer necessary. I recommend simply not using them.
I know I'm digging up an old answer here...
The issue here is that module.exports is defined after you require ClassB.
(which JohnnyHK's link shows)
Circular dependencies work great in Node, they're just defined synchronously.
When used properly, they actually solve a lot of common node issues (like accessing express.js app from other files)
Just make sure your necessary exports are defined before you require a file with a circular dependency.
This will break:
var ClassA = function(){};
var ClassB = require('classB'); //will require ClassA, which has no exports yet
module.exports = ClassA;
This will work:
var ClassA = module.exports = function(){};
var ClassB = require('classB');
I use this pattern all the time for accessing the express.js app in other files:
var express = require('express');
var app = module.exports = express();
// load in other dependencies, which can now require this file and use app
Sometimes it is really artificial to introduce a third class (as JohnnyHK advises), so in addition to Ianzz:
If you do want to replace the module.exports, for example if you're creating a class (like the b.js file in the above example), this is possible as well, just make sure that in the file that is starting the circular require, the 'module.exports = ...' statement happens before the require statement.
a.js (the main file run with node)
var ClassB = require("./b");
var ClassA = function() {
this.thing = new ClassB();
this.property = 5;
}
var a = new ClassA();
module.exports = a;
b.js
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
util.log(a.property);
}
module.exports = ClassB;
var a = require("./a"); // <------ this is the only necessary change
The solution is to 'forward declare' your exports object before requiring any other controller. So if you structure all your modules like this and you won't run into any issues like that:
// Module exports forward declaration:
module.exports = {
};
// Controllers:
var other_module = require('./other_module');
// Functions:
var foo = function () {
};
// Module exports injects:
module.exports.foo = foo;
What about lazy requiring only when you need to? So your b.js looks as follows
var ClassB = function() {
}
ClassB.prototype.doSomethingLater() {
var a = require("./a"); //a.js has finished by now
util.log(a.property);
}
module.exports = ClassB;
Of course it is good practice to put all require statements on top of the file. But there are occasions, where I forgive myself for picking something out of an otherwise unrelated module. Call it a hack, but sometimes this is better than introducing a further dependency, or adding an extra module or adding new structures (EventEmitter, etc)
You can solve this easily: just export your data before you require anything else in modules where you use module.exports:
classA.js
class ClassA {
constructor(){
ClassB.someMethod();
ClassB.anotherMethod();
};
static someMethod () {
console.log( 'Class A Doing someMethod' );
};
static anotherMethod () {
console.log( 'Class A Doing anotherMethod' );
};
};
module.exports = ClassA;
var ClassB = require( "./classB.js" );
let classX = new ClassA();
classB.js
class ClassB {
constructor(){
ClassA.someMethod();
ClassA.anotherMethod();
};
static someMethod () {
console.log( 'Class B Doing someMethod' );
};
static anotherMethod () {
console.log( 'Class A Doing anotherMethod' );
};
};
module.exports = ClassB;
var ClassA = require( "./classA.js" );
let classX = new ClassB();
A solution which require minimal change is extending module.exports instead of overriding it.
a.js - app entry point and module which use method do from b.js*
_ = require('underscore'); //underscore provides extend() for shallow extend
b = require('./b'); //module `a` uses module `b`
_.extend(module.exports, {
do: function () {
console.log('doing a');
}
});
b.do();//call `b.do()` which in turn will circularly call `a.do()`
b.js - module which use method do from a.js
_ = require('underscore');
a = require('./a');
_.extend(module.exports, {
do: function(){
console.log('doing b');
a.do();//Call `b.do()` from `a.do()` when `a` just initalized
}
})
It will work and produce:
doing b
doing a
While this code will not work:
a.js
b = require('./b');
module.exports = {
do: function () {
console.log('doing a');
}
};
b.do();
b.js
a = require('./a');
module.exports = {
do: function () {
console.log('doing b');
}
};
a.do();
Output:
node a.js
b.js:7
a.do();
^
TypeError: a.do is not a function
The important thing is not to re-assign the module.exports object that you have been given, because that object may have already been given to other modules in the cycle! Just assign properties inside module.exports and other modules will see them appear.
So a simple solution is:
module.exports.firstMember = ___;
module.exports.secondMember = ___;
The only real downside is the need to repeat module.exports. many times.
Similar to lanzz and setec's answers, I have been using the following pattern, which feels more declarative:
module.exports = Object.assign(module.exports, {
firstMember: ___,
secondMember: ___,
});
The Object.assign() copies the members into the exports object that has already been given to other modules.
The = assignment is logically redundant, since it is just setting module.exports to itself, but I am using it because it helps my IDE (WebStorm) to recognise that firstMember is a property of this module, so "Go To -> Declaration" (Cmd-B) and other tooling will work from other files.
This pattern is not very pretty, so I only use it when a cyclic dependency issue needs to be resolved.
It is fairly well suited to the reveal pattern, because you can easily add and remove exports from the object, especially when using ES6's property shorthand.
Object.assign(module.exports, {
firstMember,
//secondMember,
});
the extremely simple solution is often:
usually you'd have the require at the top of the file ...
var script = require('./script')
function stuff() {
script.farfunction()
}
instead, just require it "in the function"
function stuff() {
var _script = require('./script')
_script.farfunction()
}
An other method I've seen people do is exporting at the first line and saving it as a local variable like this:
let self = module.exports = {};
const a = require('./a');
// Exporting the necessary functions
self.func = function() { ... }
I tend to use this method, do you know about any downsides of it?
TL;DR
Just use exports.someMember = someMember instead of module.exports = { // new object }.
Extended Answer
After reading lanzz's response I could finally figure it out what is happening here, so I'll give my two cents on the subject, extending his answer.
Let's see this example:
a.js
console.log("a starting");
console.log("a requires b");
const b = require("./b");
console.log("a gets b =", b);
function functionA() {
console.log("function a");
}
console.log("a done");
exports.functionA = functionA;
b.js
console.log("b starting");
console.log("b requires a");
const a = require("./a");
console.log("b gets a =", a);
function functionB() {
console.log("On b, a =", a)
}
console.log("b done");
exports.functionB = functionB;
main.js
const a = require("./a");
const b = require("./b");
b.functionB()
Output
a starting
a requires b
b starting
b requires a
b gets a = {}
b done
a gets b = { functionB: [Function: functionB] }
a done
On b, a = { functionA: [Function: functionA] }
Here we can see that at first b receives an empty object as a, and then once a is fully loaded, that reference is updated through exports.functionA = functionA. If you instead replace the entire module with another object, through module.exports, then b will lose the reference from a, since it will point out to the same empty object from the beginning, instead of pointing to the new one.
So if you export a like this: module.exports = { functionA: functionA }, then the output will be:
a starting
a requires b
b starting
b requires a
b gets a = {}
b done
a gets b = { functionB: [Function: functionB] }
a done
On b, a = {} // same empty object
Actually I ended up requiring my dependency with
var a = null;
process.nextTick(()=>a=require("./a")); //Circular reference!
not pretty, but it works. It is more understandable and honest than changing b.js (for example only augmenting modules.export), which otherwise is perfect as is.
Here is a quick workaround that I've found use full.
On file 'a.js'
let B;
class A{
constructor(){
process.nextTick(()=>{
B = require('./b')
})
}
}
module.exports = new A();
On the file 'b.js' write the following
let A;
class B{
constructor(){
process.nextTick(()=>{
A = require('./a')
})
}
}
module.exports = new B();
This way on the next iteration of the event loop classes will be defined correctly and those require statements will work as expected.
One way to avoid it is to don't require one file in other just pass it as an argument to a function what ever you need in an another file.
By this way circular dependency will never arise.
If you just can't eliminate circular dependencies (e.g useraccount <---> userlogin), there's one more option...
Its as simple as using setTimeout()
//useraccount.js
let UserLogin = {};
setTimeout(()=>UserLogin=require('./userlogin.js'), 10);
class UserAccount{
getLogin(){
return new UserLogin(this.email);
}
}
//userlogin.js
let UserAccount ={};
setTimeout(()=>UserAccount=require('./useraccount.js'), 15);
class UserLogin{
getUser(){
return new User(this.token);
}
}

How to modularize a legacy JavaScript project

I need to use webpack to build a legacy JS project that so far did not have a
build system.
The project is split up into ~30 JS files, all of which assign functions and
fields to a single global myApp mega-object.
Previously, all these files were included separately in one namespace. It looked
somewhat like this:
myApp.js:
const myApp = {
saySomething: function(x) {
console.log(x);
},
something: "something"
};
someModule.js:
myApp.anotherModule = {
foo: function(x) {
myApp.someModule.bar(x);
}
};
anotherModule.js:
myApp.someModule = {
bar: function(x) {
myApp.saySomething(x);
},
start: function() {
myApp.someModule.foo(myApp.something);
}
};
The entrypoint would call myApp.someModule.start(), the control flow would
weave between the different parts of the mega-object.
I tried factoring out an index.js like so:
const myApp = require('./myApp');
myApp.someModule = require('./someModule');
myApp.anotherModule = require('./anotherModule');
(with the appropriate module.exports declarations in the respective files.)
But when e.g. anotherModule's start function calls myApp.someModule.foo(),
that's not in scope. I can't bring it into scope with require in the module
itself — I'd have to include someModule, which would in turn have to include
anotherModule, etc.
Is there a way out of this mess without having to refactor the entire project
(and utterly break the test suite, etc.?)
In other words: can I use webpack to assemble a mega-object and not isolate its parts' respective scope?
you should pass a myApp reference to the require
require('./someModule')(myApp);
and the module should export a function accepting myApp as parameter
myApp.anotherModule = function(myApp) {
return {
foo: function(x) {
myApp.someModule.bar(x);
}
}
};
so
myApp.someModule = require('./someModule')(myApp);
executes the function and returns your object with functions binded to myApp

Closure Compiler - obfuscate public methods - inconsistent behavior?

I just started using Closure Compiler, and I'm seeing some inconsistent behavior regarding obfuscation of public object methods.
I'm using grunt-closure-compiler - here's my grunt config:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
'closure-compiler': {
app: {
closurePath: 'closure-compiler',
js: 'src/app.js',
jsOutputFile: 'js/app.min.js',
maxBuffer: 500,
options: {
compilation_level: 'ADVANCED_OPTIMIZATIONS',
language_in: 'ECMASCRIPT5_STRICT',
formatting: 'PRETTY_PRINT'
}
}
}
});
grunt.loadNpmTasks('grunt-closure-compiler');
};
And here's app.js the file I want to obfuscate:
(function() {
/**
* #constructor
*/
function MyClass() {
var map = {};
this.put = function(name, val) {
map[name] = val;
};
this.get = function(name) {
return map[name];
};
}
var mapper = new MyClass();
mapper.put("first", 123);
alert(mapper.get("first"));
})();
(function() {
/**
* #constructor
*/
function Foo() {
var private_member_1 = 'bla';
this.someMethod = function(param1, param2) {
// do some stuff
console.log('abc');
return private_member_1;
};
// etc...
}
var foo = new Foo();
var value = foo.someMethod();
console.log(value + value);
})();
And this is the output after running grunt closure-compiler:app
'use strict';(function() {
var a = new function() {
var a = {};
this.put = function(b, c) {
a[b] = c;
};
this.get = function(b) {
return a[b];
};
};
a.put("first", 123);
alert(a.get("first"));
})();
(function() {
var a = (new function() {
this.a = function() {
console.log("abc");
return "bla";
};
}).a();
console.log(a + a);
})();
Notice that in the first closure the methods put and get were not obfuscated, while in the second closure the method someMethod was obfuscated.
Why does this happen? And how can I cause all public methods in all of my classes (like put and get) to be obfuscated as well?
Please note -
I am willing to use a different tool other than Closure Compiler to achieve this.
I want to use this with TypeScript, i.e. obfuscate the compiled TypeScript code, this is why I have many public methods.
Some specific methods are API methods that should not be obfuscated. So I need a way to tell the obfuscator which methods to skip.
Update
As of the 20150315 release of Closure-compiler, the type based optimizations are enabled by default.
This is actually covered in the project FAQ.
The option you want is use_types_for_optimization. This will enable property renaming even if a property of the same name is defined on an unrelated object.
The comprehensive list of properties which can only be renamed with this flag is huge: any property name defined on any object in an extern file.
I figured it out - get and put are considered reserved words, and closure compiler ignores them on purpose.
I ran across a list of these reserved words earlier, but I can't find it now... would appreciate if someone posts a link to the complete list.

Categories