How to correctly modularize a node.js project? - javascript

I'm creating a node.js project following the class constructor pattern:
function my_class(x,y){
this.x = x;
this.y = y;
}
The starting point of the project is the main.js file. Any class of the project must be able to access global objects (such as "world" and "socket") which are defined on main.js. I found 4 options:
I define my classes inside main.js. They'll have access to main.js's globals for being on it's closure, but main.js will become bloated.
I move the class to another file such as my_class.js and require() it. This doesn't work because my_class's instances will lose the closure context and no longer be able to access main.js's globals.
I move the class to another file and manually inject dependencies to it's constructor (ex: my_class(world,socket)). The problem is, code becomes much more complicated and weird semantics such as "my_instance.world" pop on the source, which is nonsense because "world" is not property of my_class.
I move the class to another file and require it using my_class = eval(fs.readFileSync(()) instead of require. This works just fine as my_class gets main.js's closure context, and is the solution I'm using, but seems hacky.
Which is the right way to modularize such node.js project?

If I understood you correctly the possible solution:
main.js:
(function(){
var global = "test"; // this you wanna have as a closure
var my_class = require('./my_class')(global);
my_class.go();
})();
my_class.js:
module.exports = function(global){
return {
go: function(){
console.log(global);
}
};
};
So it's similar to your 3. option

Your problem seems tricky because you have a circular dependency: main.js depends on the functionality of my_class and my_class depends on the data of main.js.
By putting the data of main.js into the global object you resolve the circular dependency:
main.js depends on the functionality of my_class.js
main.js depends on the data in the global object
my_class.js depends on the data in the global object
Now, to get rid of putting the data into the global object, implement a third module in let us say data.js. Then you require the sources like this:
main.js requires data.js
main.js requires my_class.js
my_class.js requires data.js
Since modules in node.js are singletons both main.js and my_class.js will get the same instance of data.js.

If you want to make variables in main.js available anywhere, then you can assign properties to the global object. See node.js global variables? for example. It would work fine as long as you don't over do it. With Neo's solution, you gain a little more flexibility for example with testing, because you can "inject" an arbitrary object into the module. Not every module has to use the same "global" per se.

Related

JavaScript Avoiding the global namespace pollution by objects created using constructor pattern

For creating a JS library, I am internally creating objects using constructor pattern. Now each type of object is in it's own file, so say book is in book.js. All the files are concatenated and then minified.
book.js
--------
function Book (data) {
this.data = data;
}
Book.prototype.rent = function(name) {
console.log("Rent the book to " + name);
}
Now once the page with the library is loaded, I can notice that from the browser console one can create book objects directly.
var b = new Book("somedata");
I see 2 issues here
pollution of the global namespace since the Book() object is now visible in the global scope.
Security issue as any one can create objects without namespace from console.
The library is actually under a namespace using a revealing module pattern. Is there anyway the issues I have mentioned above can be safely handled? Anyway to hide the objects from global namespace (console)?
What you can do is that you can use require module on server side and create grunt task to run browserify task on entry point file so that all your code will be converted into one file and won't be accessible from global namespace. checkout http://browserify.org for more information.
Security issue as any one can create objects without namespace from console.
That's not an issue, anyone can create objects on your namespace from the console as well.
pollution of the global namespace since the Book() object is now visible in the global scope.
The library is actually under a namespace using a revealing module pattern.
If you are loading all those files as scripts then they will put the classes declared therein in the global namespace. It's unavoidable to use the global namespace somehow, but you can put all of your objects on that custom library namespace right away, using the revealing module pattern. You would need to wrap each of those files in an IEFE that attaches the respective class to City.Library:
City.Library.Book = (function() {
function Book (data) {
this.data = data;
}
Book.prototype.rent = function(name) {
console.log("Rent the book to " + name);
};
return Book;
}());
Alternatively, treat the files as modules (ES6 is preferred) and let a module loader/bundler do this work for you automatedly.
You can wrap them in closures to keep them away from global, but, there is a fundamental problem with this—you want your functions/constructors/whatevers to be accessible!
Approaches like browserify wrap code in files in closures but keeps track of them so that when you need them you can access them. It uses commonJS modules as a means of accessing and organising modular code. I would suggest reading documentation for browserify as using it would solve both problems, although it would enforce a module system on your end users (I'd say this is generally a good thing, at least it is a worthwhile thing, but, that is for you to decide based on your specific case)
I should also point out that there are other solutions for writing modular code as well, such as webpack or jspm

Javascript global declaration

I've just started out with javascript and came across this line in a file called global.js There is only one line in the file. I'm not sure what does App do. Any ideas?
Filename: globals.js
//The Application
App = {};
it creates an object with a name of App... that's all it does.
I would assume that the idea behind the global.js file in your case is to include the file in your base html/template so that the variables in there can be accessed from anywhere in the app.
In some of our projects, we've had global files like this containing references to collections and "setting" variables, which is quite handy :)
It is creating an object named App in the global namespace. App has no functions or attributes (yet).
It (implicitly) declares a variable called App in a "global" context and assigns an empty object as its value. Assuming this is used on a web page somewhere, it's the same as declaring window.App = {}.
How this affects the rest of your application, we won't know until you post more relevant code.
This script just instantiate this empty Object. Probably, others scripts that ran along with this uses that object and depends that it is created there.

What's the correct way to use script files from other script files Meteor?

According to an answer to this question and the Meteor documentation, Meteor will automatically include all scripts in a package folder structure recursively with the deepest first. However, when I define a js class in a script in MyProject/sever folder the class is undefined if referenced from a top-level .js file. If I move the class definition to my top-level .js file above the if (Meteor.isServer) the class is defined correctly. What am I missing in structuring or including my javascript from external files?
EDIT:
The issue is more fundamental than just seeing my js class. I can't call a function or see anything in that private namespace that meteor 0.6 creates. Obviously there must be some way to reference stuff defined in another file or large projects wouldn't be possible in meteor.
As I suspected, this was related to my misunderstanding of javascript's (goofy hack) class declarations and globals. Changing:
function ClassFoo(){
this.bar = function(){}
}
to
ClassFoo = function ClassFoo(){
this.bar = function(){}
}
fixed it by making ClassFoo global. FWIW, note that var ClassFoo = ... will NOT work because it then becomes local to the auto-generated closure's namespace. Gotta love javascript's quirks.

Creating a "controller" script for Node.js

I'm creating a program in Node.js. I'm pretty new to programming anything other than small javascript functions for websites so please bear with me if my terminology/ideas are totally wrong.
I originally had the entire program in one giant (~500 line) script file. Several people suggested I split it up into separate classes, where each class only has one 'job' to complete. I like this idea as it has helped me really streamline my code and make it more modular and manageable.
My issue is: How do I access these classes from a central file?
For instance, pretend I have 3 classes, in 3 separate javascript files, all containing 3 functions each. I want to access and pass data to/from all of these from one central "controller" script. What's the best way to do this? Can I just require it into a variable, then access the script's functions like so?
var class1 = require('./class1.js');
class1.function1(); // call the first function contained in class1.js
Is such a thing even possible? Again, totally new to this.
NodeJS supports CommonJS modules. A CommonJS module provides three global variables: module, exports and require.
You can export your API by adding to the exports object and require these files just like other node modules (add ./ to indicate that it is relative to the current file), assign it to a variable and access the values you added to that files exports object:
// first-module.js
exports.hello = 'world';
exports.num = 23;
// main.js
var first = require('./first-module');
console.log(first.hello);
console.log(first.num);
You need to add functions to the exports object in class1.js.
require("./class1") will return this object.

How to manage multiple JS files server-side with Node.js

I'm working on a project with Node.js and the server-side code is becoming large enough that I would like to split it off into multiple files. It appears this has been done client-side for ages, development is done by inserting a script tag for each file and only for distribution is something like "Make" used to put everything together. I realize there's no point in concatting all the server-side code so I'm not asking how to do that. The closest thing I can find to use is require(), however it doesn't behave quite like script does in the browser in that require'd files do not share a common namespace.
Looking at some older Node.js projects, like Shooter, it appears this was once not the case, that or I'm missing something really simple in my code. My require'd files cannot access the global calling namespace at compile time nor run time. Is there any simple way around this or are we forced to make all our require'd JS files completely autonomous from the calling scope?
You do not want a common namespace because globals are evil. In node we define modules
// someThings.js
(function() {
var someThings = ...;
...
module.exports.getSomeThings = function() {
return someThings();
}
}());
// main.js
var things = require("someThings");
...
doSomething(things.getSomeThings());
You define a module and then expose a public API for your module by writing to exports.
The best way to handle this is dependency injection. Your module exposes an init function and you pass an object hash of dependencies into your module.
If you really insist on accessing global scope then you can access that through global. Every file can write and read to the global object. Again you do not want to use globals.
re #Raynos answer, if the module file is next to the file that includes it, it should be
var things = require("./someThings");
If the module is published on, and installed through, npm, or explicitly put into the ./node_modules/ folder, then the
var things = require("someThings");
is correct.

Categories

Resources