I created a javascript application with all of the code in one file. The application has grown quite a bit and I think it's time to split it up into multiple files, but I'm having a hard time figuring out how to do this. I think the problem lies with how I have decided to build the app, which uses the following template:
var myApp = function(){
//there are several global variables that all of the modules use;
var global1, global2, module1, module2;
global1 = {
prop1:1
};
//There are also several functions that are shared between modules
function globalFunction(){
}
var ModuleOne = function(){
function doSomething(){
//using the global function
globalFunction();
}
return{
doSomething:doSomething
}
};
var ModuleTwo = function(){
function doSomething(){
//module 2 also needs the global function
globalFunction();
//Use the functionality in module 1
//I can refactor this part to be loosely coupled/event driven
module1.doSomething();
}
};
module1 = new ModuleOne();
module2 = new ModuleTwo();
};
Even if all of the modules were loosely coupled and event driven, I still don't know how I would go about splitting this into multiple files given each module's reliance on the shared functions/variables. Does anyone have suggestions?
Take a look at the design pattern in this article: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth - you can split your module definition across multiple files in a way that lets common properties be shared but also lets you create variables or methods that are private just to a particular file.
The basic idea is that the individual JS files add to the same module with code like this:
var MODULE = (function (my) {
var privateToThisFile = "something";
// add capabilities...
my.publicProperty = "something";
return my;
}(MODULE || {}));
Where in each JS file if MODULE is already defined (from another JS file) you add to it otherwise you create it. You can set it up so that it (mostly) doesn't matter what order the various files are included in.
The article details several variations, and of course you'll probably come up with your own tweaks...
not to add to the confusion, but coming from a C++ background, I've tried to construct something that resembles something like a c++ namespace in the manner described below. it works, but I'd like to know if this is an acceptable pattern for the OP ?
--------------------------------file main.js:----------------
var namespacename = function(){}
namespacename.mainvalue = 5;
namespacename.maintest = function() {
var cm = new namespacename.game();
cm.callme();
}
--------------------------------file game.js:----------------
namespacename.gamevalue = 15;
namespacename.game = function(){
this.callme = function(){
console.log( "callme" );
}
}
namespacename.gametest = function() {
console.log( "gametest:gamevalue:" + this.gamevalue );
console.log( "gametest:mainvalue:" + this.mainvalue );
}
--------------------------------file index.html:--------------
<html>
<head>
<title>testbed</title>
</head>
<body onload="init();">
</body>
<script type="text/javascript" src="main.js"></script>
<script type="text/javascript" src="game.js"></script>
<script type="text/javascript">
init = function()
{
namespacename.maintest();
namespacename.gametest();
console.log( "html main:" + namespacename.mainvalue );
console.log( "html game:" + namespacename.gamevalue );
}
</script>
</html>
Give require.js a shot. http://requirejs.org/
Example:
require(["dir/file"], function() {
// Called when file.js loads
});
You can put the shared functions and shared modules on the myApp object so they don't pollute the global namespace, but can be accessed anywhere without being inside the same closure.
myApp.moduleOne = function() {...}
myApp.moduleTwo = function() {...}
myApp.globalFunction = function() {...}
Then, you can define them in any file and use them in any file.
You could also just break the file up into multiple files, but require them to be included in a specific order that preserves your closure. If you're breaking up the files for practical editing reasons, but recombining and minimizing them for actual deployment, then this wouldn't cost you anything in terms of how you write code or how it's deployed, but would give you lots of smaller files for editing convenience.
My favorite solution to this is use server side scripting to include the other files inside my "main" file. For example, using Perl's Template Toolkit:
var myApp = function(){
[% INCLUDE lib/module1.js %]
[% INCLUDE lib/module2.js %]
[% INCLUDE lib/module3.js %]
}
Or PHP:
var myApp = function(){
<?php
include 'lib/module1.js';
include 'lib/module2.js';
?>
}
Related
I am working on supporting a REST API that literally has thousands of functions/objects/stats/etc., and placing all those calls into one file does not strike me as very maintainable. What I want to do is have a 'base' file that has the main constructor function, a few utility and very common functions, and then files for each section of API calls.
The Problem: How do you attach functions from other files to the 'base' Object so that referencing the main object allows for access from the subsections you have added to your program??
Let me try and illustrate what I am looking to do:
1) 'base' file has the main constructor:
var IPAddr = "";
var Token = "";
exports.Main = function(opts) {
IPAddr = opts.IPAddr;
Token = opts.Token;
}
2) 'file1' has some subfunctions that I want to define:
Main.prototype.Function1 = function(callback) {
// stuff done here
callback(error, data);
}
Main.prototype.Function2 = function(callback) {
// stuff done here
callback(error,data);
}
3) Program file brings it all together:
var Main = require('main.js');
var Main?!? = require('file1.js');
Main.Function1(function(err,out) {
if(err) {
// error stuff here
}
// main stuff here
}
Is there a way to combine an Object from multiple code files?? A 120,000 line Node.JS file just doesn't seem to be the way to go to me....not to mention it takes too long to load! Thanks :)
SOLUTION: For those who may stumble upon this in the future... I took the source code for Object.assign and back ported it to my v0.12 version of Node and got it working.
I used the code from here: https://github.com/sindresorhus/object-assign/blob/master/index.js and put it in a separate file that I just require('./object-assign.js') without assigning it to a var. Then my code looks something like this:
require('./object-assign.js');
var Main = require('./Main.js');
Object.assign(Main.prototype, require('./file1.js'));
Object.assign(Main.prototype, require('./file2.js'));
And all my functions from the two files show up under the Main() Object...too cool :)
At first each file works in its own scope, so all local variables are not shared.
However, as hacky approach, you may just add Main into global scope available everywhere by writing global.Main = Main right after you define it, please make sure that you require main file first in list of requires.
The better(who said?) approach is to extend prototype of Main later, but in this case you may need to update a lot of code. Just mix-in additional functionality into base class
file1.js
module.exports = {
x: function() {/*****/}
}
index.js
var Main = require('main.js');
Object.assign(Main.prototype, require('file1.js'));
Shure.
constructor.js
module.exports = function(){
//whatever
};
prototype.js
module.exports = {
someMethod(){ return "test";}
};
main.js
const Main = require("./constructor.js");
Object.assign( Main.prototype, require("./prototype.js"));
Thus far I've worked only with relatively small projects (and mostly alone), but this time I have to collaborate with other programmers... basically because of that I must plan the structure of the website very carefully for the avoidance of spending hours debugging the code.
At this point I suppose doing that in the following manner. I divide my code in modules and store each module in a separate file inside an object (or a function) with a made-up name (lzheA, lzheB, lzheC etc.) to avoid conflicts whether an object with the same name was used in an another piece of code. When the document is loaded, I declare a variable (an object) that I use as a main namespace of the application. Properties of the object are the modules I defined before.
// file BI.lib.js
var lzheA = {
foo: function() {
},
bar: function() {
},
}
// file BI.init.js
function lzheK() {
BI.loadPage();
}
// file BI.loadPage.js
function lzheC() {
var result = document.getElementById('result');
result.innerHTML = "that worked";
}
// and so on
var lzheA,lzheB,lzheD,lzheE,lzheF,lzheG,lzheH,lzheI,lzheJ;
// doing the following when the document is loaded
var BI = {
lib: lzheA,
menu: lzheB,
loadPage: lzheC,
customScripts: lzheD,
_index: lzheE,
_briefs: lzheF,
_shop: lzheG,
_cases: lzheH,
_blog: lzheI,
_contacts: lzheJ,
init: lzheK,
}
BI.init();
https://jsfiddle.net/vwc2og57/2/
The question... is this way of structuring worth living or did I miss something because of lack of experience? Would the made-up names of the modules confuse you regardless of the fact that each one used only twice - while declaring the variable and assigning it to a property?
I consider the namespaces a good option when you want to modularize applications in Javascript. But I declare them in a different way
var myModule = myModule || {}; // This will allow to use the module in other places, declaring more than one specificComponent in other js file for example
myModule.specificComponent = (function(){
// Private things
var myVar = {};
var init = function() {
// Code
};
return {
init: init // Public Stuff
};
})();
If you want to call the init method, you would call it like this
myModule.specificComponent.init();
With this approach, i guarantee that the module will not be overwritten by another declaration in another place, and also I can declare internal components into my namespaces.
Also, the trick of just exposing what you want inside the return block, will make your component safer and you will be encapsulating your code in a pretty way.
Hope it helps
I've got some problems splitting up my jquery source code into more than one file. My real source code is a bit more complicated but the following simple example shows my problem very good. At first I would like to show you a working example with only one javascript file. Afterwards, I will describe what I tried in order to split the javascript into two files.
My html code looks like this ("./jquery" is a symbolic link to my local jquery download):
<html>
<head>
<script src="./jquery"></script>
<script src="./file1.js"></script>
</head>
<body>
<div id="content"></div>
</body>
</html>
The jquery source code in file1.js looks like this:
$(document).ready(function() {
var Test = (function() {
var content = $('#content');
var init = function() {
content.html('<p>test</p>');
};
return {
init: init
}
})();
Test.init();
});
After opening the page, "test" is displayed so that this example works as expected.
But now I want to put the whole Test part into another file file2.js. My html is basically the same but gets an additional line:
<script src="./file2.js"></script>
file1.js now contains only the call of the init function:
$(document).ready(function() {
Test.init();
});
and file2.js contains the definition of Test:
var Test = (function() {
var content = $('#content');
var init = function() {
content.html('<p>test</p>');
};
return {
init: init
}
})();
When I open the page, "test" is not displayed any more. In order to make sure that the init function is called at all, I added a console.log("test"); to the init function which is working fine. Therefore, I suppose that the function might be called before the DOM is ready, but actually I am pretty clueless. Maybe someone can give me a hint how to make that run.
Best regards and thanks in advance!
You can do several things according to your preferences...
1. Move your scripts to the end of the HTML file intead than in header...
<html>
<head>
</head>
<body>
<div id="content"></div>
</body>
<script src="./jquery"></script>
<script src="./file2.js"></script>
<script src="./file1.js"></script>
</html>
Think this problem secuencially... if you don't want to declare a var in each module referring an element in your DOM you need that the element exists first, then you can declare the "global" var to the module content. This way your original file2.js works.
Another way is to declare the content "global" to your module but init this in your init function...
var Test = (function() {
var content;
var init = function() {
content = $('#content');
content.html('<p>test</p>');
};
return {
init: init
}
})();
Now you can use the content variable in all of your module's functions.
Hope this helps, let me know.
file1 depends on file2. Make sure file1 comes ordinally after file2 in your html.
AngularJS offers dependency injection, modules, services, factories and all sorts of other goodness. Takes a bit to get used to, but well worth it IMO: much cleaner abstraction of javascript from DOM, data from presentation etc.
I appreciate your question is JQuery specific, but especially if you're starting a new site, I suggest you give Angular a try.
Modify your file2.js as follows:
var Test = {
content : $('#content'),
init : function() {
Test.content.html('<p>test</p>');
}
//, include other functions here
};
Modify your file1.js as follows:
$(document).ready(function(){
Test.init();
})
Now declare file2.js before your declare file1.js because file1.js is referencing a function from file2.js .
I have a site that uses a javascript object to hold various functions and variable data.
var Site = {
Page: {
...some functions...
},
Player: {
...more functions and variables...
}
}
The problem I'm faced with is that the header file where the script resides has grown to around 500 lines of code. I would like to break the sections like Page and Player up into separate files for easier manipulation. An obstacle of this is that some of the functions rely on output from PHP, and must remain on the base page. Is there a way that I can include separate files into the object and preserve the structure already in place?
Note that by convention, variables starting with a capital letter are reserved for constructors.
File 1:
var Site = Site || {};
Site.Page = {
...some functions...
}
File 2:
var Site = Site || {};
Site.Player = {
...more functions...
};
You can also use an extend function so that you declare an object literal, then copy the proerties and values to a base object. Or you can use an IIFE to assign functions. This is handy if you are doing feature detection and creating different functions depending on the outcome.
var Site = Site || {};
(function(global) {
function Player() {
// stuff
}
global.Site.Player = Player;
if (test) {
global.Site.someFn = function() {
// stuff 1
};
} else {
global.Site.someFn = function() {
// stuff 2
};
}
...
}(this));
or some version of the above.
Don't mix data with logic. That is, "some of the functions rely on output from PHP" is a code smell. If you have code like this:
setSomeContent("<? echo $myobj->title() ?>");
setMoreContent("<? echo $myobj->description() ?>");
Then it's time to backup a bit.
First, it's easy to break your JS up. Just make a script tag for each file like so.
<script src="main.js"></script>
<script src="page.js"></script>
<script src="player.js"></script>
Now they are loaded in order, so we can be sure main is loaded first.
// main.js
var Site = {
// functions
};
// page.js
Site.Page = {
// functions
};
// player.js
Site.Player = {
// functions
};
Now as for you data from PHP, export it to the page as JSON, stored in it's own variable:
var myObj = <? echo myObj->toJSON() ?>;
Site.Page.setContentForObject(myObj);
Which is then passed entirely to whatever function you have declared in your JS files. Separation of data and logic remains fairly clean this way.
We are starting a new project and we have decided to use javascript ""namespaces"" to organize our client side code. The thing is that we have noticed that we can end very easily with super-long namespaces that are dificult to remember like
myProject.components.myComponent.doSomethig();
Is there any better way to do this or create some kind of "alias" somehow?
Thanks.
In JavaScript, you can make shortcut references to long namespaces stuff
var myComp = myProject.components.myComponent;
myComp.func1();
This is a reference only. You can do this with other long names and write less like this
var getEl = document.getElementById,
myEl = getEl('divId');
Also you can organize your code with RequireJS to organize your code
// file: myProject/components/myComponent.js
define(function(){
var myComponent ={};
myComponent.func1 = function(){
...
}
return myComponent;
});
// file: myProject/main.js
require(['myProject/components/myComponent', 'myProject/components/myComponent2'],
function(comp1, comp2){
var main = {};
main.init = function() {
...
comp1.func1();
}
});
// file: myProject/index.html
<script src="libs/require.js" data-main="myProject/main"></script>
If you use scoping functions around your module code (and if you don't, you should), then you can create local aliases quite easily as variables shared by all of the functions within a given module.
E.g., code defining the myComponent component:
(function() {
var comp = {};
// Export our component
myProject.components.myComponent = comp;
// add things to `comp`; since `comp` and `myProject.components.myComponent`
// refer to the same object, adding to `comp` is adding to the one object
// they both refer to and so you can access those things via either reference
})();
Similarly if you're writing app code that uses multiple components:
(function() {
var thisComp = myProject.components.thisComponent,
thatComp = myProject.components.thatComponent;
// Use `thisComp` and `thatComp`
})();
You can always store a subnamespace in a local variable:
var myComponent = myProject.components.myComponent;