Creating a "controller" script for Node.js - javascript

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.

Related

Why not add classes to window or global in a namespaced variable?

I am using webpack to transpile/bundle/etc my js files. Im using the import/export syntax ( as opposed to the CommonJS way of require and export.module ). This means i need to import each class and all subclasses of it however many times if i need to use them in the context of a specific script.
The question:
Even though classes arent natively supported in js, why do we need to import them all the time? Wouldnt it be easier if ( and im only speaking for classes ) they were available to all scopes?
EDIT: To avoid polluting the global scope one could do something like global.myLibs and be done with that issue. I personally prefix my classes with something unique but this method would serve even those that dont i suppose.
For example:
window.myClasses could serve as a container for all my classes. I come from an iOS background where all the classes in a main "bundle", in java i think that would be a "package" are available to everyone. Re-importing the class itself doesnt seem like it serves any purpose.
See here:
Why do i need to import modules everytime in webpack bundle?
and here: Bundling js files with webpack class undefined
Adding things in the global scope can lead you to naming conflicts. What if you created a class named Node, add it to global scope by doing window.Node = Node ? You lose the reference to the browser's global Node object.
You can argue that you will never use names that are already used for global objects. But now, what if in a year or so, a new object is added to the spec with the same name as one of yours, and you want to use it alongside your own object ? You have to make a choice, or rename your own object. This is not future proof.
Importing the same module in every module that uses it is a best practice. Because by doing it, you never pollute the global scope. Don't be afraid that it imports the code of this module n times in your final bundle. Webpack imports it only one time, then uses a reference to the module everytime you are importing it.
See these resources :
JavaScript Modules: A Beginner’s Guide by Preethi Kasireddy on Medium
Eloquent Javascript Modules chapter

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

How to use javascript constant in javascript file from another javascript file

I have created one javascript file in which I have declared different string constants.
now in another javascript file I want to use those String constants from already created javascript file.
Is there any way to do this.
Thanks in advance.
If you declare your constants in file1 as global variables:
var someConstant = 42;
Then you can just use that variable in your other JS files. Just make sure file1 is loaded before you try to use them.
However, polluting the global scope like this come with it's risks, as those variables are easily changed.
Multiple ways.
Concatenate
Use a task runner like grunt to define a task that concatenates your files into a single one. This will not only allow convenient definition of constants but also improve performance.
There are other tools to do this, too. See Prepros for windows and codekit for Macs.
Modularize
If you are on client side, use a tool like require.js or browserify to define commonJS / AMD modules and require them as you need.
If you are on server side using node, this works out of the box for commonJS.
Load scripts in correct order, expose them through global objects.
You could load your constant defining script first and do something like this:
var constants = {
MY_CONST: 'Foo'
}
Your main, whi script could access this variable. If you omit the var keyword, the variable becomes globally available. Note however that this should be avoided.
You could even add a property to the global object (window on the client side).
Personally I like to use commonJS modules when working on projects that allow me to do so. Rob Ashton has an opinion on this that I would like to share.
When I can't use those modules in a convenient way, which would be the case when working with (custom) web-components because of their isolated scopes, I like to add a single script which creates
an Object like App. I use this object to expose modules, services & constants which can then be required by any component in a neat way:
App.myService.doSomething()
Create a file which contains all the constants and variables
Constants.js
const EMAIL = "xyz#gmail.com"
const PHONE = "9911223344"
var NAME = "Default name"
Access the Constants.js file in your HTML file
xyz.html
<script src="Constants.js"></script>
Now you can access the Constants in any of file inside a project

Transitioning code to RequireJS

TL;DR at the bottom of the question, for those who don't want to read all my junk.
My current method of JavaScript modularization is to simply create a global anchor, like "csc" (my company acronym) and then start tacking modules onto that.
So I'll end up with a global structure like:
csc.
Utils
Map
.Geolocation
Storage.
Cookie
DB
And each of these files are stored in a directory structure:
csc.js
csc.Utils.js
csc.Map.js
csc.Storage.js
This eliminates the need to load my entire codebase all the time.
I'm trying to transition toward using RequireJS, but the methodology employed by that library seems to be a bit different.
In order to maintain my namespaced structure, I could define modules around all of my modules, but still tack them into the global "csc" reference. However this seems to go against the core principles of Require.
Without keeping them global, however, I lose my nice namespacing, such as "csc.Map.Geolocation" because I now have a bunch of separate variables, like so:
require(['csc', 'csc.Utils', 'csc.Map'], function (csc, utils, map) {
});
I'll strip my question down to its essence, in case my horrible description above didn't suffice:
Is there a way, perhaps within the module definitions, to combine these three variables back into the structure defined at the top of this question? Or am I going about this all wrong, and should I instead be adhering to the Require way of doing things?
I'd love to follow the Require methodology, but I also love the ability to have all of my modules chainable and namespaced.
Don't be discouraged by the documentation's example path hierarchy, notice that require does not strictly enforce any particular convention. You are free to design and follow your own convention.
Utils, Map, and Storage all become directories. The base actions that they perform should be named module.js in their respective directories, like so:
core.js
Utils/
module.js
Map/
module.js
geolocation.module.js
Storage/
module.js
cookie.module.js
db.module.js
The module.js files include and return their children. Here is an example of Storage/module.js:
require(["Storage/cookie", "Storage/db"], function (cookie, db) {
var Storage = {};
// do whatever you need with Storage
Storage.cookie = cookie
Storage.db = db
return Storage
});
Notice also the core.js file in root. This file would work just the same,
require(["Utils/module", "Storage/module", "Map/module"], function (utils, storage, map) {
var Core = {};
// do whatever you need with Storage
Core.Utils = utils
Core.Storage = storage
Core.Map = map
return Core
});
Now, require core.js wherever you will need access to these modules (every file basically). Yes, this will load all of the involved files all of the time in development, but when you compile your app, all of your variables will be inside the scope of an anonymous function, and not directly accessible via the window object.
Again, tweak this as you see fit, it's your own convention.

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